parent
447116a93c
commit
9340af1a8a
13 changed files with 878 additions and 21 deletions
@ -0,0 +1,105 @@ |
|||||||
|
// This file is part of OpenCV project.
|
||||||
|
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||||
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
|
|
||||||
|
#ifndef OPENCV_CORE_ASYNC_HPP |
||||||
|
#define OPENCV_CORE_ASYNC_HPP |
||||||
|
|
||||||
|
#include <opencv2/core/mat.hpp> |
||||||
|
|
||||||
|
#ifdef CV_CXX11 |
||||||
|
//#include <future>
|
||||||
|
#include <chrono> |
||||||
|
#endif |
||||||
|
|
||||||
|
namespace cv { |
||||||
|
|
||||||
|
/** @addtogroup core_async
|
||||||
|
|
||||||
|
@{ |
||||||
|
*/ |
||||||
|
|
||||||
|
|
||||||
|
/** @brief Returns result of asynchronous operations
|
||||||
|
|
||||||
|
Object has attached asynchronous state. |
||||||
|
Assignment operator doesn't clone asynchronous state (it is shared between all instances). |
||||||
|
|
||||||
|
Result can be fetched via get() method only once. |
||||||
|
|
||||||
|
*/ |
||||||
|
class CV_EXPORTS_W AsyncArray |
||||||
|
{ |
||||||
|
public: |
||||||
|
~AsyncArray() CV_NOEXCEPT; |
||||||
|
CV_WRAP AsyncArray() CV_NOEXCEPT; |
||||||
|
AsyncArray(const AsyncArray& o) CV_NOEXCEPT; |
||||||
|
AsyncArray& operator=(const AsyncArray& o) CV_NOEXCEPT; |
||||||
|
CV_WRAP void release() CV_NOEXCEPT; |
||||||
|
|
||||||
|
/** Fetch the result.
|
||||||
|
@param[out] dst destination array |
||||||
|
|
||||||
|
Waits for result until container has valid result. |
||||||
|
Throws exception if exception was stored as a result. |
||||||
|
|
||||||
|
Throws exception on invalid container state. |
||||||
|
|
||||||
|
@note Result or stored exception can be fetched only once. |
||||||
|
*/ |
||||||
|
CV_WRAP void get(OutputArray dst) const; |
||||||
|
|
||||||
|
/** Retrieving the result with timeout
|
||||||
|
@param[out] dst destination array |
||||||
|
@param[in] timeoutNs timeout in nanoseconds, -1 for infinite wait |
||||||
|
|
||||||
|
@returns true if result is ready, false if the timeout has expired |
||||||
|
|
||||||
|
@note Result or stored exception can be fetched only once. |
||||||
|
*/ |
||||||
|
bool get(OutputArray dst, int64 timeoutNs) const; |
||||||
|
|
||||||
|
CV_WRAP inline |
||||||
|
bool get(OutputArray dst, double timeoutNs) const { return get(dst, (int64)timeoutNs); } |
||||||
|
|
||||||
|
bool wait_for(int64 timeoutNs) const; |
||||||
|
|
||||||
|
CV_WRAP inline |
||||||
|
bool wait_for(double timeoutNs) const { return wait_for((int64)timeoutNs); } |
||||||
|
|
||||||
|
CV_WRAP bool valid() const CV_NOEXCEPT; |
||||||
|
|
||||||
|
#ifdef CV_CXX11 |
||||||
|
inline AsyncArray(AsyncArray&& o) { p = o.p; o.p = NULL; } |
||||||
|
inline AsyncArray& operator=(AsyncArray&& o) CV_NOEXCEPT { std::swap(p, o.p); return *this; } |
||||||
|
|
||||||
|
template<typename _Rep, typename _Period> |
||||||
|
inline bool get(OutputArray dst, const std::chrono::duration<_Rep, _Period>& timeout) |
||||||
|
{ |
||||||
|
return get(dst, (int64)(std::chrono::nanoseconds(timeout).count())); |
||||||
|
} |
||||||
|
|
||||||
|
template<typename _Rep, typename _Period> |
||||||
|
inline bool wait_for(const std::chrono::duration<_Rep, _Period>& timeout) |
||||||
|
{ |
||||||
|
return wait_for((int64)(std::chrono::nanoseconds(timeout).count())); |
||||||
|
} |
||||||
|
|
||||||
|
#if 0 |
||||||
|
std::future<Mat> getFutureMat() const; |
||||||
|
std::future<UMat> getFutureUMat() const; |
||||||
|
#endif |
||||||
|
#endif |
||||||
|
|
||||||
|
|
||||||
|
// PImpl
|
||||||
|
struct Impl; friend struct Impl; |
||||||
|
inline void* _getImpl() const CV_NOEXCEPT { return p; } |
||||||
|
protected: |
||||||
|
Impl* p; |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
//! @}
|
||||||
|
} // namespace
|
||||||
|
#endif // OPENCV_CORE_ASYNC_HPP
|
@ -0,0 +1,71 @@ |
|||||||
|
// This file is part of OpenCV project.
|
||||||
|
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||||
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
|
|
||||||
|
#ifndef OPENCV_CORE_ASYNC_PROMISE_HPP |
||||||
|
#define OPENCV_CORE_ASYNC_PROMISE_HPP |
||||||
|
|
||||||
|
#include "../async.hpp" |
||||||
|
|
||||||
|
#include "exception_ptr.hpp" |
||||||
|
|
||||||
|
namespace cv { |
||||||
|
|
||||||
|
/** @addtogroup core_async
|
||||||
|
@{ |
||||||
|
*/ |
||||||
|
|
||||||
|
|
||||||
|
/** @brief Provides result of asynchronous operations
|
||||||
|
|
||||||
|
*/ |
||||||
|
class CV_EXPORTS AsyncPromise |
||||||
|
{ |
||||||
|
public: |
||||||
|
~AsyncPromise() CV_NOEXCEPT; |
||||||
|
AsyncPromise() CV_NOEXCEPT; |
||||||
|
explicit AsyncPromise(const AsyncPromise& o) CV_NOEXCEPT; |
||||||
|
AsyncPromise& operator=(const AsyncPromise& o) CV_NOEXCEPT; |
||||||
|
void release() CV_NOEXCEPT; |
||||||
|
|
||||||
|
/** Returns associated AsyncArray
|
||||||
|
@note Can be called once |
||||||
|
*/ |
||||||
|
AsyncArray getArrayResult(); |
||||||
|
|
||||||
|
/** Stores asynchronous result.
|
||||||
|
@param[in] value result |
||||||
|
*/ |
||||||
|
void setValue(InputArray value); |
||||||
|
|
||||||
|
// TODO "move" setters
|
||||||
|
|
||||||
|
#if CV__EXCEPTION_PTR |
||||||
|
/** Stores exception.
|
||||||
|
@param[in] exception exception to be raised in AsyncArray |
||||||
|
*/ |
||||||
|
void setException(std::exception_ptr exception); |
||||||
|
#endif |
||||||
|
|
||||||
|
/** Stores exception.
|
||||||
|
@param[in] exception exception to be raised in AsyncArray |
||||||
|
*/ |
||||||
|
void setException(const cv::Exception& exception); |
||||||
|
|
||||||
|
#ifdef CV_CXX11 |
||||||
|
explicit AsyncPromise(AsyncPromise&& o) { p = o.p; o.p = NULL; } |
||||||
|
AsyncPromise& operator=(AsyncPromise&& o) CV_NOEXCEPT { std::swap(p, o.p); return *this; } |
||||||
|
#endif |
||||||
|
|
||||||
|
|
||||||
|
// PImpl
|
||||||
|
typedef struct AsyncArray::Impl Impl; friend struct AsyncArray::Impl; |
||||||
|
inline void* _getImpl() const CV_NOEXCEPT { return p; } |
||||||
|
protected: |
||||||
|
Impl* p; |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
//! @}
|
||||||
|
} // namespace
|
||||||
|
#endif // OPENCV_CORE_ASYNC_PROMISE_HPP
|
@ -0,0 +1,27 @@ |
|||||||
|
// This file is part of OpenCV project.
|
||||||
|
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||||
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
|
|
||||||
|
#ifndef OPENCV_CORE_DETAILS_EXCEPTION_PTR_H |
||||||
|
#define OPENCV_CORE_DETAILS_EXCEPTION_PTR_H |
||||||
|
|
||||||
|
#ifndef CV__EXCEPTION_PTR |
||||||
|
# if defined(__ANDROID__) && defined(ATOMIC_INT_LOCK_FREE) && ATOMIC_INT_LOCK_FREE < 2 |
||||||
|
# define CV__EXCEPTION_PTR 0 // Not supported, details: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58938
|
||||||
|
# elif defined(CV_CXX11) |
||||||
|
# define CV__EXCEPTION_PTR 1 |
||||||
|
# elif defined(_MSC_VER) |
||||||
|
# define CV__EXCEPTION_PTR (_MSC_VER >= 1600) |
||||||
|
# elif defined(__clang__) |
||||||
|
# define CV__EXCEPTION_PTR 0 // C++11 only (see above)
|
||||||
|
# elif defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__) |
||||||
|
# define CV__EXCEPTION_PTR (__GXX_EXPERIMENTAL_CXX0X__ > 0) |
||||||
|
# endif |
||||||
|
#endif |
||||||
|
#ifndef CV__EXCEPTION_PTR |
||||||
|
# define CV__EXCEPTION_PTR 0 |
||||||
|
#elif CV__EXCEPTION_PTR |
||||||
|
# include <exception> // std::exception_ptr
|
||||||
|
#endif |
||||||
|
|
||||||
|
#endif // OPENCV_CORE_DETAILS_EXCEPTION_PTR_H
|
@ -0,0 +1,8 @@ |
|||||||
|
#ifdef HAVE_OPENCV_CORE |
||||||
|
|
||||||
|
#include "opencv2/core/async.hpp" |
||||||
|
|
||||||
|
CV_PY_TO_CLASS(AsyncArray); |
||||||
|
CV_PY_FROM_CLASS(AsyncArray); |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,366 @@ |
|||||||
|
// This file is part of OpenCV project.
|
||||||
|
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||||
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
|
|
||||||
|
#include "precomp.hpp" |
||||||
|
//#undef CV_CXX11 // debug non C++11 mode
|
||||||
|
#include "opencv2/core/async.hpp" |
||||||
|
#include "opencv2/core/detail/async_promise.hpp" |
||||||
|
|
||||||
|
#include "opencv2/core/cvstd.hpp" |
||||||
|
|
||||||
|
#include <opencv2/core/utils/logger.defines.hpp> |
||||||
|
#undef CV_LOG_STRIP_LEVEL |
||||||
|
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_DEBUG + 1 |
||||||
|
#include <opencv2/core/utils/logger.hpp> |
||||||
|
|
||||||
|
|
||||||
|
#ifdef CV_CXX11 |
||||||
|
#include <mutex> |
||||||
|
#include <condition_variable> |
||||||
|
#include <chrono> |
||||||
|
#endif |
||||||
|
|
||||||
|
namespace cv { |
||||||
|
|
||||||
|
/**
|
||||||
|
Manages shared state of asynchronous result |
||||||
|
*/ |
||||||
|
struct AsyncArray::Impl |
||||||
|
{ |
||||||
|
int refcount; |
||||||
|
void addrefFuture() CV_NOEXCEPT { CV_XADD(&refcount_future, 1); CV_XADD(&refcount, 1); } \
|
||||||
|
void releaseFuture() CV_NOEXCEPT { CV_XADD(&refcount_future, -1); if(1 == CV_XADD(&refcount, -1)) delete this; } \
|
||||||
|
int refcount_future; |
||||||
|
void addrefPromise() CV_NOEXCEPT { CV_XADD(&refcount_promise, 1); CV_XADD(&refcount, 1); } \
|
||||||
|
void releasePromise() CV_NOEXCEPT { CV_XADD(&refcount_promise, -1); if(1 == CV_XADD(&refcount, -1)) delete this; } \
|
||||||
|
int refcount_promise; |
||||||
|
|
||||||
|
#ifdef CV_CXX11 |
||||||
|
mutable std::mutex mtx; |
||||||
|
mutable std::condition_variable cond_var; |
||||||
|
#else |
||||||
|
mutable cv::Mutex mtx; |
||||||
|
#endif |
||||||
|
|
||||||
|
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) |
||||||
|
{ |
||||||
|
if(refcount_promise == 0) |
||||||
|
CV_Error(Error::StsInternal, "Asynchronous result producer has been destroyed"); |
||||||
|
if (!wait_for(timeoutNs)) |
||||||
|
return false; |
||||||
|
} |
||||||
|
#ifdef CV_CXX11 |
||||||
|
std::unique_lock<std::mutex> lock(mtx); |
||||||
|
#else |
||||||
|
cv::AutoLock lock(mtx); |
||||||
|
#endif |
||||||
|
if (has_result) |
||||||
|
{ |
||||||
|
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'"); |
||||||
|
} |
||||||
|
CV_Assert(!has_result); |
||||||
|
CV_Assert(timeoutNs < 0); |
||||||
|
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_LOG_INFO(NULL, "Waiting for async result ..."); |
||||||
|
#ifdef CV_CXX11 |
||||||
|
std::unique_lock<std::mutex> lock(mtx); |
||||||
|
const auto cond_pred = [&]{ return has_result == true; }; |
||||||
|
if (timeoutNs > 0) |
||||||
|
return cond_var.wait_for(lock, std::chrono::nanoseconds(timeoutNs), cond_pred); |
||||||
|
else |
||||||
|
{ |
||||||
|
cond_var.wait(lock, cond_pred); |
||||||
|
CV_Assert(has_result); |
||||||
|
return true; |
||||||
|
} |
||||||
|
#else |
||||||
|
CV_Error(Error::StsNotImplemented, "OpenCV has been built without async waiting support (C++11 is required)"); |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
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"); |
||||||
|
#ifdef CV_CXX11 |
||||||
|
std::unique_lock<std::mutex> lock(mtx); |
||||||
|
#else |
||||||
|
cv::AutoLock lock(mtx); |
||||||
|
#endif |
||||||
|
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; |
||||||
|
#ifdef CV_CXX11 |
||||||
|
cond_var.notify_all(); |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
#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"); |
||||||
|
#ifdef CV_CXX11 |
||||||
|
std::unique_lock<std::mutex> lock(mtx); |
||||||
|
#else |
||||||
|
cv::AutoLock lock(mtx); |
||||||
|
#endif |
||||||
|
CV_Assert(!has_result); |
||||||
|
has_exception = true; |
||||||
|
exception = e; |
||||||
|
has_result = true; |
||||||
|
#ifdef CV_CXX11 |
||||||
|
cond_var.notify_all(); |
||||||
|
#endif |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
void setException(const cv::Exception e) |
||||||
|
{ |
||||||
|
if (future_is_returned && refcount_future == 0) |
||||||
|
CV_Error(Error::StsError, "Associated AsyncArray has been destroyed"); |
||||||
|
#ifdef CV_CXX11 |
||||||
|
std::unique_lock<std::mutex> lock(mtx); |
||||||
|
#else |
||||||
|
cv::AutoLock lock(mtx); |
||||||
|
#endif |
||||||
|
CV_Assert(!has_result); |
||||||
|
has_exception = true; |
||||||
|
cv_exception = e; |
||||||
|
has_result = true; |
||||||
|
#ifdef CV_CXX11 |
||||||
|
cond_var.notify_all(); |
||||||
|
#endif |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
AsyncArray::AsyncArray() CV_NOEXCEPT |
||||||
|
: p(NULL) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
AsyncArray::~AsyncArray() CV_NOEXCEPT |
||||||
|
{ |
||||||
|
release(); |
||||||
|
} |
||||||
|
|
||||||
|
AsyncArray::AsyncArray(const AsyncArray& o) CV_NOEXCEPT |
||||||
|
: p(o.p) |
||||||
|
{ |
||||||
|
if (p) |
||||||
|
p->addrefFuture(); |
||||||
|
} |
||||||
|
|
||||||
|
AsyncArray& AsyncArray::operator=(const AsyncArray& o) CV_NOEXCEPT |
||||||
|
{ |
||||||
|
Impl* newp = o.p; |
||||||
|
if (newp) |
||||||
|
newp->addrefFuture(); |
||||||
|
release(); |
||||||
|
p = newp; |
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
void AsyncArray::release() CV_NOEXCEPT |
||||||
|
{ |
||||||
|
Impl* impl = p; |
||||||
|
p = NULL; |
||||||
|
if (impl) |
||||||
|
impl->releaseFuture(); |
||||||
|
} |
||||||
|
|
||||||
|
bool AsyncArray::get(OutputArray dst, int64 timeoutNs) const |
||||||
|
{ |
||||||
|
CV_Assert(p); |
||||||
|
return p->get(dst, timeoutNs); |
||||||
|
} |
||||||
|
|
||||||
|
void AsyncArray::get(OutputArray dst) const |
||||||
|
{ |
||||||
|
CV_Assert(p); |
||||||
|
bool res = p->get(dst, -1); |
||||||
|
CV_Assert(res); |
||||||
|
} |
||||||
|
|
||||||
|
bool AsyncArray::wait_for(int64 timeoutNs) const |
||||||
|
{ |
||||||
|
CV_Assert(p); |
||||||
|
return p->wait_for(timeoutNs); |
||||||
|
} |
||||||
|
|
||||||
|
bool AsyncArray::valid() const CV_NOEXCEPT |
||||||
|
{ |
||||||
|
if (!p) return false; |
||||||
|
return p->valid(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// AsyncPromise
|
||||||
|
//
|
||||||
|
|
||||||
|
AsyncPromise::AsyncPromise() CV_NOEXCEPT |
||||||
|
: p(new AsyncArray::Impl()) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
AsyncPromise::~AsyncPromise() CV_NOEXCEPT |
||||||
|
{ |
||||||
|
release(); |
||||||
|
} |
||||||
|
|
||||||
|
AsyncPromise::AsyncPromise(const AsyncPromise& o) CV_NOEXCEPT |
||||||
|
: p(o.p) |
||||||
|
{ |
||||||
|
if (p) |
||||||
|
p->addrefPromise(); |
||||||
|
} |
||||||
|
|
||||||
|
AsyncPromise& AsyncPromise::operator=(const AsyncPromise& o) CV_NOEXCEPT |
||||||
|
{ |
||||||
|
Impl* newp = o.p; |
||||||
|
if (newp) |
||||||
|
newp->addrefPromise(); |
||||||
|
release(); |
||||||
|
p = newp; |
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
void AsyncPromise::release() CV_NOEXCEPT |
||||||
|
{ |
||||||
|
Impl* impl = p; |
||||||
|
p = NULL; |
||||||
|
if (impl) |
||||||
|
impl->releasePromise(); |
||||||
|
} |
||||||
|
|
||||||
|
AsyncArray AsyncPromise::getArrayResult() |
||||||
|
{ |
||||||
|
CV_Assert(p); |
||||||
|
return p->getArrayResult(); |
||||||
|
} |
||||||
|
|
||||||
|
void AsyncPromise::setValue(InputArray value) |
||||||
|
{ |
||||||
|
CV_Assert(p); |
||||||
|
return p->setValue(value); |
||||||
|
} |
||||||
|
|
||||||
|
void AsyncPromise::setException(const cv::Exception& exception) |
||||||
|
{ |
||||||
|
CV_Assert(p); |
||||||
|
return p->setException(exception); |
||||||
|
} |
||||||
|
|
||||||
|
#if CV__EXCEPTION_PTR |
||||||
|
void AsyncPromise::setException(std::exception_ptr exception) |
||||||
|
{ |
||||||
|
CV_Assert(p); |
||||||
|
return p->setException(exception); |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
} // namespace
|
@ -0,0 +1,154 @@ |
|||||||
|
// This file is part of OpenCV project.
|
||||||
|
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||||
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
|
#include "test_precomp.hpp" |
||||||
|
#include <opencv2/core/async.hpp> |
||||||
|
#include <opencv2/core/detail/async_promise.hpp> |
||||||
|
|
||||||
|
#include <opencv2/core/bindings_utils.hpp> |
||||||
|
|
||||||
|
#ifdef CV_CXX11 |
||||||
|
#include <thread> |
||||||
|
#include <chrono> |
||||||
|
#endif |
||||||
|
|
||||||
|
namespace opencv_test { namespace { |
||||||
|
|
||||||
|
TEST(Core_Async, BasicCheck) |
||||||
|
{ |
||||||
|
Mat m(3, 3, CV_32FC1, Scalar::all(5.0f)); |
||||||
|
AsyncPromise p; |
||||||
|
AsyncArray r = p.getArrayResult(); |
||||||
|
EXPECT_TRUE(r.valid()); |
||||||
|
|
||||||
|
// Follow the limitations of std::promise::get_future
|
||||||
|
// https://en.cppreference.com/w/cpp/thread/promise/get_future
|
||||||
|
EXPECT_THROW(AsyncArray r2 = p.getArrayResult(), cv::Exception); |
||||||
|
|
||||||
|
p.setValue(m); |
||||||
|
|
||||||
|
Mat m2; |
||||||
|
r.get(m2); |
||||||
|
EXPECT_EQ(0, cvtest::norm(m, m2, NORM_INF)); |
||||||
|
|
||||||
|
// Follow the limitations of std::future::get
|
||||||
|
// https://en.cppreference.com/w/cpp/thread/future/get
|
||||||
|
EXPECT_FALSE(r.valid()); |
||||||
|
Mat m3; |
||||||
|
EXPECT_THROW(r.get(m3), cv::Exception); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(Core_Async, ExceptionCheck) |
||||||
|
{ |
||||||
|
Mat m(3, 3, CV_32FC1, Scalar::all(5.0f)); |
||||||
|
AsyncPromise p; |
||||||
|
AsyncArray r = p.getArrayResult(); |
||||||
|
EXPECT_TRUE(r.valid()); |
||||||
|
|
||||||
|
try |
||||||
|
{ |
||||||
|
CV_Error(Error::StsOk, "Test: Generated async error"); |
||||||
|
} |
||||||
|
catch (const cv::Exception& e) |
||||||
|
{ |
||||||
|
p.setException(e); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
Mat m2; |
||||||
|
r.get(m2); |
||||||
|
FAIL() << "Exception is expected"; |
||||||
|
} |
||||||
|
catch (const cv::Exception& e) |
||||||
|
{ |
||||||
|
EXPECT_EQ(Error::StsOk, e.code) << e.what(); |
||||||
|
} |
||||||
|
|
||||||
|
// Follow the limitations of std::future::get
|
||||||
|
// https://en.cppreference.com/w/cpp/thread/future/get
|
||||||
|
EXPECT_FALSE(r.valid()); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
TEST(Core_Async, LikePythonTest) |
||||||
|
{ |
||||||
|
Mat m(3, 3, CV_32FC1, Scalar::all(5.0f)); |
||||||
|
AsyncArray r = cv::utils::testAsyncArray(m); |
||||||
|
EXPECT_TRUE(r.valid()); |
||||||
|
Mat m2; |
||||||
|
r.get(m2); |
||||||
|
EXPECT_EQ(0, cvtest::norm(m, m2, NORM_INF)); |
||||||
|
|
||||||
|
// Follow the limitations of std::future::get
|
||||||
|
// https://en.cppreference.com/w/cpp/thread/future/get
|
||||||
|
EXPECT_FALSE(r.valid()); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
#ifdef CV_CXX11 |
||||||
|
TEST(Core_Async, AsyncThread_Simple) |
||||||
|
{ |
||||||
|
Mat m(3, 3, CV_32FC1, Scalar::all(5.0f)); |
||||||
|
AsyncPromise p; |
||||||
|
AsyncArray r = p.getArrayResult(); |
||||||
|
|
||||||
|
std::thread t([&]{ |
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100)); |
||||||
|
try { |
||||||
|
p.setValue(m); |
||||||
|
} catch (const std::exception& e) { |
||||||
|
std::cout << e.what() << std::endl; |
||||||
|
} catch (...) { |
||||||
|
std::cout << "Unknown C++ exception" << std::endl; |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
try |
||||||
|
{ |
||||||
|
Mat m2; |
||||||
|
r.get(m2); |
||||||
|
EXPECT_EQ(0, cvtest::norm(m, m2, NORM_INF)); |
||||||
|
|
||||||
|
t.join(); |
||||||
|
} |
||||||
|
catch (...) |
||||||
|
{ |
||||||
|
t.join(); |
||||||
|
throw; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
TEST(Core_Async, AsyncThread_DetachedResult) |
||||||
|
{ |
||||||
|
Mat m(3, 3, CV_32FC1, Scalar::all(5.0f)); |
||||||
|
AsyncPromise p; |
||||||
|
{ |
||||||
|
AsyncArray r = p.getArrayResult(); |
||||||
|
r.release(); |
||||||
|
} |
||||||
|
|
||||||
|
bool exception_ok = false; |
||||||
|
|
||||||
|
std::thread t([&]{ |
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100)); |
||||||
|
try { |
||||||
|
p.setValue(m); |
||||||
|
} catch (const cv::Exception& e) { |
||||||
|
if (e.code == Error::StsError) |
||||||
|
exception_ok = true; |
||||||
|
else |
||||||
|
std::cout << e.what() << std::endl; |
||||||
|
} catch (const std::exception& e) { |
||||||
|
std::cout << e.what() << std::endl; |
||||||
|
} catch (...) { |
||||||
|
std::cout << "Unknown C++ exception" << std::endl; |
||||||
|
} |
||||||
|
}); |
||||||
|
t.join(); |
||||||
|
|
||||||
|
EXPECT_TRUE(exception_ok); |
||||||
|
} |
||||||
|
|
||||||
|
#endif |
||||||
|
|
||||||
|
}} // namespace
|
@ -0,0 +1,33 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
from __future__ import print_function |
||||||
|
|
||||||
|
import numpy as np |
||||||
|
import cv2 as cv |
||||||
|
|
||||||
|
from tests_common import NewOpenCVTests |
||||||
|
|
||||||
|
class AsyncTest(NewOpenCVTests): |
||||||
|
|
||||||
|
def test_async_simple(self): |
||||||
|
m = np.array([[1,2],[3,4],[5,6]]) |
||||||
|
async_result = cv.utils.testAsyncArray(m) |
||||||
|
self.assertTrue(async_result.valid()) |
||||||
|
ret, result = async_result.get(timeoutNs=10**6) # 1ms |
||||||
|
self.assertTrue(ret) |
||||||
|
self.assertFalse(async_result.valid()) |
||||||
|
self.assertEqual(cv.norm(m, result, cv.NORM_INF), 0) |
||||||
|
|
||||||
|
|
||||||
|
def test_async_exception(self): |
||||||
|
async_result = cv.utils.testAsyncException() |
||||||
|
self.assertTrue(async_result.valid()) |
||||||
|
try: |
||||||
|
_ret, _result = async_result.get(timeoutNs=10**6) # 1ms |
||||||
|
self.fail("Exception expected") |
||||||
|
except cv.error as e: |
||||||
|
self.assertEqual(cv.Error.StsOk, e.code) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__': |
||||||
|
NewOpenCVTests.bootstrap() |
Loading…
Reference in new issue