mirror of
https://github.com/opencv/opencv.git
synced 2024-11-28 13:10:12 +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"
|
||||
|
||||
|
||||
#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;
|
||||
|
||||
namespace cv
|
||||
@ -169,7 +191,7 @@ namespace
|
||||
{
|
||||
public:
|
||||
ParallelLoopBodyWrapperContext(const cv::ParallelLoopBody& _body, const cv::Range& _r, double _nstripes) :
|
||||
is_rng_used(false)
|
||||
is_rng_used(false), hasException(false)
|
||||
{
|
||||
|
||||
body = &_body;
|
||||
@ -189,7 +211,7 @@ namespace
|
||||
pThreadRoot = cv::instr::getInstrumentTLSStruct().pCurrentNode;
|
||||
#endif
|
||||
}
|
||||
~ParallelLoopBodyWrapperContext()
|
||||
void finalize()
|
||||
{
|
||||
#ifdef ENABLE_INSTRUMENTATION
|
||||
for(size_t i = 0; i < pThreadRoot->m_childs.size(); i++)
|
||||
@ -209,7 +231,17 @@ namespace
|
||||
if (traceRootRegion)
|
||||
CV_TRACE_NS::details::parallelForFinalize(*traceRootRegion);
|
||||
#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;
|
||||
cv::Range wholeRange;
|
||||
@ -223,6 +255,32 @@ namespace
|
||||
#ifdef ENABLE_INSTRUMENTATION
|
||||
cv::instr::InstrNode *pThreadRoot;
|
||||
#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:
|
||||
ParallelLoopBodyWrapperContext(const ParallelLoopBodyWrapperContext&); // disabled
|
||||
ParallelLoopBodyWrapperContext& operator=(const ParallelLoopBodyWrapperContext&); // disabled
|
||||
@ -273,7 +331,29 @@ namespace
|
||||
CV_TRACE_ARG_VALUE(range_end, "range.end", (int64)r.end);
|
||||
#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))
|
||||
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
|
||||
|
||||
#endif
|
||||
|
||||
ctx.finalize(); // propagate exceptions if exists
|
||||
}
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user