core: propagate parallel_for() exceptions

This commit is contained in:
Alexander Alekhin 2018-03-30 14:57:51 +03:00
parent 8c4b5b6a70
commit 6f69800d0c

View File

@ -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
{