1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 15:53:03 +04:00

Merge pull request #19985 from fpetrogalli:disable_threads

* [build][option] Introduce `OPENCV_DISABLE_THREAD_SUPPORT` option.

The option forces the library to build without thread support.

* update handling of OPENCV_DISABLE_THREAD_SUPPORT

- reduce amount of #if conditions

* [to squash] cmake: apply mode vars in toolchains too

Co-authored-by: Alexander Alekhin <alexander.a.alekhin@gmail.com>
This commit is contained in:
Francesco Petrogalli
2021-07-08 21:21:21 +01:00
committed by GitHub
parent 59ae0e0013
commit b928ebdd53
16 changed files with 435 additions and 16 deletions
+4
View File
@@ -153,6 +153,10 @@ if(OPENCV_CORE_EXCLUDE_C_API)
ocv_target_compile_definitions(${the_module} PRIVATE "OPENCV_EXCLUDE_C_API=1")
endif()
if(OPENCV_DISABLE_THREAD_SUPPORT)
ocv_target_compile_definitions(${the_module} PUBLIC "OPENCV_DISABLE_THREAD_SUPPORT=1")
endif()
if(HAVE_HPX)
ocv_target_link_libraries(${the_module} LINK_PRIVATE "${HPX_LIBRARIES}")
endif()
+19 -1
View File
@@ -714,9 +714,27 @@ void Mat::forEach_impl(const Functor& operation) {
/////////////////////////// Synchronization Primitives ///////////////////////////////
#if !defined(_M_CEE)
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
typedef std::recursive_mutex Mutex;
typedef std::lock_guard<cv::Mutex> AutoLock;
#endif
#else // OPENCV_DISABLE_THREAD_SUPPORT
// Custom (failing) implementation of `std::recursive_mutex`.
struct Mutex {
void lock(){
CV_Error(cv::Error::StsNotImplemented,
"cv::Mutex is disabled by OPENCV_DISABLE_THREAD_SUPPORT=ON");
}
void unlock(){
CV_Error(cv::Error::StsNotImplemented,
"cv::Mutex is disabled by OPENCV_DISABLE_THREAD_SUPPORT=ON");
}
};
// Stub for cv::AutoLock when threads are disabled.
struct AutoLock {
AutoLock(Mutex &) { }
};
#endif // OPENCV_DISABLE_THREAD_SUPPORT
#endif // !defined(_M_CEE)
/** @brief Designed for command line parsing
+166
View File
@@ -14,6 +14,7 @@
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_DEBUG + 1
#include <opencv2/core/utils/logger.hpp>
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
#ifdef CV_CXX11
#include <mutex>
@@ -236,6 +237,171 @@ struct AsyncArray::Impl
}
};
} // namespace
#else // OPENCV_DISABLE_THREAD_SUPPORT
namespace cv {
// no threading
struct AsyncArray::Impl
{
int refcount;
void addrefFuture() CV_NOEXCEPT { refcount_future++; refcount++; }
void releaseFuture() CV_NOEXCEPT { refcount_future--; if (0 == --refcount) delete this; }
int refcount_future;
void addrefPromise() CV_NOEXCEPT { refcount_promise++; refcount++; } \
void releasePromise() CV_NOEXCEPT { refcount_promise--; if (0 == --refcount) delete this; }
int refcount_promise;
mutable bool has_result; // Mat, UMat or exception
mutable cv::Ptr<Mat> result_mat;
mutable cv::Ptr<UMat> result_umat;
bool has_exception;
#if CV__EXCEPTION_PTR
std::exception_ptr exception;
#endif
cv::Exception cv_exception;
mutable bool result_is_fetched;
bool future_is_returned;
Impl()
: refcount(1), refcount_future(0), refcount_promise(1)
, has_result(false)
, has_exception(false)
, result_is_fetched(false)
, future_is_returned(false)
{
// nothing
}
~Impl()
{
if (has_result && !result_is_fetched)
{
CV_LOG_INFO(NULL, "Asynchronous result has not been fetched");
}
}
bool get(OutputArray dst, int64 timeoutNs) const
{
CV_Assert(!result_is_fetched);
if (!has_result)
{
CV_UNUSED(timeoutNs);
CV_Error(Error::StsError, "Result is not produced (unable to wait for result in OPENCV_DISABLE_THREAD_SUPPORT mode)");
}
if (!result_mat.empty())
{
dst.move(*result_mat.get());
result_mat.release();
result_is_fetched = true;
return true;
}
if (!result_umat.empty())
{
dst.move(*result_umat.get());
result_umat.release();
result_is_fetched = true;
return true;
}
#if CV__EXCEPTION_PTR
if (has_exception && exception)
{
result_is_fetched = true;
std::rethrow_exception(exception);
}
#endif
if (has_exception)
{
result_is_fetched = true;
throw cv_exception;
}
CV_Error(Error::StsInternal, "AsyncArray: invalid state of 'has_result = true'");
return false;
}
bool valid() const CV_NOEXCEPT
{
if (result_is_fetched)
return false;
if (refcount_promise == 0 && !has_result)
return false;
return true;
}
bool wait_for(int64 timeoutNs) const
{
CV_Assert(valid());
if (has_result)
return has_result;
if (timeoutNs == 0)
return has_result;
CV_Error(Error::StsError, "Unable to wait in OPENCV_DISABLE_THREAD_SUPPORT mode");
}
AsyncArray getArrayResult()
{
CV_Assert(refcount_future == 0);
AsyncArray result;
addrefFuture();
result.p = this;
future_is_returned = true;
return result;
}
void setValue(InputArray value)
{
if (future_is_returned && refcount_future == 0)
CV_Error(Error::StsError, "Associated AsyncArray has been destroyed");
CV_Assert(!has_result);
int k = value.kind();
if (k == _InputArray::UMAT)
{
result_umat = makePtr<UMat>();
value.copyTo(*result_umat.get());
}
else
{
result_mat = makePtr<Mat>();
value.copyTo(*result_mat.get());
}
has_result = true;
}
#if CV__EXCEPTION_PTR
void setException(std::exception_ptr e)
{
if (future_is_returned && refcount_future == 0)
CV_Error(Error::StsError, "Associated AsyncArray has been destroyed");
CV_Assert(!has_result);
has_exception = true;
exception = e;
has_result = true;
}
#endif
void setException(const cv::Exception e)
{
if (future_is_returned && refcount_future == 0)
CV_Error(Error::StsError, "Associated AsyncArray has been destroyed");
CV_Assert(!has_result);
has_exception = true;
cv_exception = e;
has_result = true;
}
};
}
#endif // OPENCV_DISABLE_THREAD_SUPPORT
namespace cv {
AsyncArray::AsyncArray() CV_NOEXCEPT
: p(NULL)
+9 -1
View File
@@ -72,7 +72,7 @@
#endif
#endif
#if defined CV_CXX11
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
#include <thread>
#endif
@@ -884,6 +884,7 @@ T minNonZero(const T& val_1, const T& val_2)
return (val_1 != 0) ? val_1 : val_2;
}
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
static
int getNumberOfCPUs_()
{
@@ -986,6 +987,13 @@ int getNumberOfCPUs()
return nCPUs; // cached value
}
#else // OPENCV_DISABLE_THREAD_SUPPORT
int getNumberOfCPUs()
{
return 1;
}
#endif // OPENCV_DISABLE_THREAD_SUPPORT
const char* currentParallelFramework()
{
std::shared_ptr<ParallelForAPI>& api = getCurrentParallelForAPI();
+112
View File
@@ -216,7 +216,9 @@ std::wstring GetTempFileNameWinRT(std::wstring prefix)
#endif
#else
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
#include <pthread.h>
#endif
#include <sys/time.h>
#include <time.h>
@@ -1366,6 +1368,8 @@ bool __termination = false;
namespace details {
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
#ifdef _WIN32
#ifdef _MSC_VER
#pragma warning(disable:4505) // unreferenced local function has been removed
@@ -1778,14 +1782,122 @@ static void WINAPI opencv_fls_destructor(void* pData)
#endif // CV_USE_FLS
#endif // _WIN32
#else // OPENCV_DISABLE_THREAD_SUPPORT
// no threading (OPENCV_DISABLE_THREAD_SUPPORT=ON)
class TlsStorage
{
public:
TlsStorage()
{
slots.reserve(32);
}
~TlsStorage()
{
for (size_t slotIdx = 0; slotIdx < slots.size(); slotIdx++)
{
SlotInfo& s = slots[slotIdx];
TLSDataContainer* container = s.container;
if (container && s.data)
{
container->deleteDataInstance(s.data); // Can't use from SlotInfo destructor
s.data = nullptr;
}
}
}
// Reserve TLS storage index
size_t reserveSlot(TLSDataContainer* container)
{
size_t slotsSize = slots.size();
for (size_t slot = 0; slot < slotsSize; slot++)
{
SlotInfo& s = slots[slot];
if (s.container == NULL)
{
CV_Assert(!s.data);
s.container = container;
return slot;
}
}
// create new slot
slots.push_back(SlotInfo(container));
return slotsSize;
}
// Release TLS storage index and pass associated data to caller
void releaseSlot(size_t slotIdx, std::vector<void*> &dataVec, bool keepSlot = false)
{
CV_Assert(slotIdx < slots.size());
SlotInfo& s = slots[slotIdx];
void* data = s.data;
if (data)
{
dataVec.push_back(data);
s.data = nullptr;
}
if (!keepSlot)
{
s.container = NULL; // mark slot as free (see reserveSlot() implementation)
}
}
// Get data by TLS storage index
void* getData(size_t slotIdx) const
{
CV_Assert(slotIdx < slots.size());
const SlotInfo& s = slots[slotIdx];
return s.data;
}
// Gather data from threads by TLS storage index
void gather(size_t slotIdx, std::vector<void*> &dataVec)
{
CV_Assert(slotIdx < slots.size());
SlotInfo& s = slots[slotIdx];
void* data = s.data;
if (data)
dataVec.push_back(data);
return;
}
// Set data to storage index
void setData(size_t slotIdx, void* pData)
{
CV_Assert(slotIdx < slots.size());
SlotInfo& s = slots[slotIdx];
s.data = pData;
}
private:
struct SlotInfo
{
SlotInfo(TLSDataContainer* _container) : container(_container), data(nullptr) {}
TLSDataContainer* container; // attached container (to dispose data)
void* data;
};
std::vector<struct SlotInfo> slots;
};
static TlsStorage& getTlsStorage()
{
static TlsStorage g_storage; // no threading
return g_storage;
}
#endif // OPENCV_DISABLE_THREAD_SUPPORT
} // namespace details
using namespace details;
void releaseTlsStorageThread()
{
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
if (!g_isTlsStorageInitialized)
return; // nothing to release, so prefer to avoid creation of new global structures
getTlsStorage().releaseThread();
#endif
}
TLSDataContainer::TLSDataContainer()
+33 -4
View File
@@ -56,10 +56,6 @@ void setSize(UMat& m, int _dims, const int* _sz, const size_t* _steps,
void updateContinuityFlag(UMat& m);
void finalizeHdr(UMat& m);
// it should be a prime number for the best hash function
enum { UMAT_NLOCKS = 31 };
static Mutex umatLocks[UMAT_NLOCKS];
UMatData::UMatData(const MatAllocator* allocator)
{
prevAllocator = currAllocator = allocator;
@@ -131,6 +127,12 @@ UMatData::~UMatData()
}
}
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
// it should be a prime number for the best hash function
enum { UMAT_NLOCKS = 31 };
static Mutex umatLocks[UMAT_NLOCKS];
static size_t getUMatDataLockIndex(const UMatData* u)
{
size_t idx = ((size_t)(void*)u) % UMAT_NLOCKS;
@@ -228,6 +230,33 @@ UMatDataAutoLock::~UMatDataAutoLock()
getUMatDataAutoLocker().release(u1, u2);
}
#else
void UMatData::lock()
{
// nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
}
void UMatData::unlock()
{
// nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
}
UMatDataAutoLock::UMatDataAutoLock(UMatData* u) : u1(u), u2(NULL)
{
// nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
}
UMatDataAutoLock::UMatDataAutoLock(UMatData* u1_, UMatData* u2_) : u1(u1_), u2(u2_)
{
// nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
}
UMatDataAutoLock::~UMatDataAutoLock()
{
// nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
}
#endif // OPENCV_DISABLE_THREAD_SUPPORT
//////////////////////////////// UMat ////////////////////////////////
UMat::UMat(UMatUsageFlags _usageFlags) CV_NOEXCEPT
+2 -2
View File
@@ -37,8 +37,8 @@ private:
// also, extensible functions (accepting user-provided callback) are not allowed
// to call LogTagManger (to prevent iterator invalidation), which needs enforced
// with a non-recursive mutex.
using MutexType = std::mutex;
using LockType = std::lock_guard<MutexType>;
using MutexType = cv::Mutex;
using LockType = cv::AutoLock;
enum class MatchingScope
{
+3 -2
View File
@@ -7,7 +7,7 @@
#include <opencv2/core/bindings_utils.hpp>
#ifdef CV_CXX11
#if defined(CV_CXX11) && !defined(OPENCV_DISABLE_THREAD_SUPPORT)
#include <thread>
#include <chrono>
#endif
@@ -85,7 +85,8 @@ TEST(Core_Async, LikePythonTest)
}
#ifdef CV_CXX11
#if defined(CV_CXX11) && !defined(OPENCV_DISABLE_THREAD_SUPPORT)
TEST(Core_Async, AsyncThread_Simple)
{
Mat m(3, 3, CV_32FC1, Scalar::all(5.0f));
+4 -1
View File
@@ -8,9 +8,12 @@
#include "opencv2/core/utils/logger.hpp"
#include "opencv2/core/utils/buffer_area.private.hpp"
#include "test_utils_tls.impl.hpp"
#include "opencv2/core/utils/filesystem.private.hpp"
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
#include "test_utils_tls.impl.hpp"
#endif
namespace opencv_test { namespace {
static const char * const keys =