mirror of
https://github.com/opencv/opencv.git
synced 2025-08-06 14:36:36 +08:00
Merge pull request #11197 from alalek:parallel_propagate_exception
This commit is contained in:
commit
e20fb7f429
@ -129,6 +129,28 @@
|
|||||||
|
|
||||||
#include "parallel_impl.hpp"
|
#include "parallel_impl.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef CV__EXCEPTION_PTR
|
||||||
|
# ifdef CV_CXX11
|
||||||
|
# define CV__EXCEPTION_PTR 1
|
||||||
|
# elif defined(CV_ICC)
|
||||||
|
# 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
|
||||||
|
#else
|
||||||
|
# include <exception> // std::exception_ptr
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
using namespace cv;
|
using namespace cv;
|
||||||
|
|
||||||
namespace cv
|
namespace cv
|
||||||
@ -169,7 +191,7 @@ namespace
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ParallelLoopBodyWrapperContext(const cv::ParallelLoopBody& _body, const cv::Range& _r, double _nstripes) :
|
ParallelLoopBodyWrapperContext(const cv::ParallelLoopBody& _body, const cv::Range& _r, double _nstripes) :
|
||||||
is_rng_used(false)
|
is_rng_used(false), hasException(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
body = &_body;
|
body = &_body;
|
||||||
@ -189,7 +211,7 @@ namespace
|
|||||||
pThreadRoot = cv::instr::getInstrumentTLSStruct().pCurrentNode;
|
pThreadRoot = cv::instr::getInstrumentTLSStruct().pCurrentNode;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
~ParallelLoopBodyWrapperContext()
|
void finalize()
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_INSTRUMENTATION
|
#ifdef ENABLE_INSTRUMENTATION
|
||||||
for(size_t i = 0; i < pThreadRoot->m_childs.size(); i++)
|
for(size_t i = 0; i < pThreadRoot->m_childs.size(); i++)
|
||||||
@ -209,7 +231,17 @@ namespace
|
|||||||
if (traceRootRegion)
|
if (traceRootRegion)
|
||||||
CV_TRACE_NS::details::parallelForFinalize(*traceRootRegion);
|
CV_TRACE_NS::details::parallelForFinalize(*traceRootRegion);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (hasException)
|
||||||
|
{
|
||||||
|
#if CV__EXCEPTION_PTR
|
||||||
|
std::rethrow_exception(pException);
|
||||||
|
#else
|
||||||
|
CV_ErrorNoReturn(Error::StsError, "Exception in parallel_for() body: " + exception_message);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
~ParallelLoopBodyWrapperContext() {}
|
||||||
|
|
||||||
const cv::ParallelLoopBody* body;
|
const cv::ParallelLoopBody* body;
|
||||||
cv::Range wholeRange;
|
cv::Range wholeRange;
|
||||||
@ -223,6 +255,32 @@ namespace
|
|||||||
#ifdef ENABLE_INSTRUMENTATION
|
#ifdef ENABLE_INSTRUMENTATION
|
||||||
cv::instr::InstrNode *pThreadRoot;
|
cv::instr::InstrNode *pThreadRoot;
|
||||||
#endif
|
#endif
|
||||||
|
bool hasException;
|
||||||
|
#if CV__EXCEPTION_PTR
|
||||||
|
std::exception_ptr pException;
|
||||||
|
#else
|
||||||
|
cv::String exception_message;
|
||||||
|
#endif
|
||||||
|
#if CV__EXCEPTION_PTR
|
||||||
|
void recordException()
|
||||||
|
#else
|
||||||
|
void recordException(const cv::String& msg)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (!hasException)
|
||||||
|
{
|
||||||
|
cv::AutoLock lock(cv::getInitializationMutex());
|
||||||
|
if (!hasException)
|
||||||
|
{
|
||||||
|
hasException = true;
|
||||||
|
#if CV__EXCEPTION_PTR
|
||||||
|
pException = std::current_exception();
|
||||||
|
#else
|
||||||
|
exception_message = msg;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
ParallelLoopBodyWrapperContext(const ParallelLoopBodyWrapperContext&); // disabled
|
ParallelLoopBodyWrapperContext(const ParallelLoopBodyWrapperContext&); // disabled
|
||||||
ParallelLoopBodyWrapperContext& operator=(const ParallelLoopBodyWrapperContext&); // disabled
|
ParallelLoopBodyWrapperContext& operator=(const ParallelLoopBodyWrapperContext&); // disabled
|
||||||
@ -273,7 +331,29 @@ namespace
|
|||||||
CV_TRACE_ARG_VALUE(range_end, "range.end", (int64)r.end);
|
CV_TRACE_ARG_VALUE(range_end, "range.end", (int64)r.end);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
(*ctx.body)(r);
|
try
|
||||||
|
{
|
||||||
|
(*ctx.body)(r);
|
||||||
|
}
|
||||||
|
#if CV__EXCEPTION_PTR
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
ctx.recordException();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
catch (const cv::Exception& e)
|
||||||
|
{
|
||||||
|
ctx.recordException(e.what());
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
ctx.recordException(e.what());
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
ctx.recordException("Unknown exception");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!ctx.is_rng_used && !(cv::theRNG() == ctx.rng))
|
if (!ctx.is_rng_used && !(cv::theRNG() == ctx.rng))
|
||||||
ctx.is_rng_used = true;
|
ctx.is_rng_used = true;
|
||||||
@ -486,6 +566,8 @@ static void parallel_for_impl(const cv::Range& range, const cv::ParallelLoopBody
|
|||||||
#error You have hacked and compiling with unsupported parallel framework
|
#error You have hacked and compiling with unsupported parallel framework
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ctx.finalize(); // propagate exceptions if exists
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -157,4 +157,36 @@ TEST(Core_Copy, repeat_regression_8972)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ThrowErrorParallelLoopBody : public cv::ParallelLoopBody
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ThrowErrorParallelLoopBody(cv::Mat& dst, int i) : dst_(dst), i_(i) {}
|
||||||
|
~ThrowErrorParallelLoopBody() {}
|
||||||
|
void operator()(const cv::Range& r) const
|
||||||
|
{
|
||||||
|
for (int i = r.start; i < r.end; i++)
|
||||||
|
{
|
||||||
|
CV_Assert(i != i_);
|
||||||
|
dst_.row(i).setTo(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
Mat dst_;
|
||||||
|
int i_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(Core_Parallel, propagate_exceptions)
|
||||||
|
{
|
||||||
|
Mat dst1(1000, 100, CV_8SC1, Scalar::all(0));
|
||||||
|
ASSERT_NO_THROW({
|
||||||
|
parallel_for_(cv::Range(0, dst1.rows), ThrowErrorParallelLoopBody(dst1, -1));
|
||||||
|
});
|
||||||
|
|
||||||
|
Mat dst2(1000, 100, CV_8SC1, Scalar::all(0));
|
||||||
|
ASSERT_THROW({
|
||||||
|
parallel_for_(cv::Range(0, dst2.rows), ThrowErrorParallelLoopBody(dst2, dst2.rows / 2));
|
||||||
|
}, cv::Exception);
|
||||||
|
}
|
||||||
|
|
||||||
}} // namespace
|
}} // namespace
|
||||||
|
Loading…
Reference in New Issue
Block a user