diff --git a/modules/core/src/parallel.cpp b/modules/core/src/parallel.cpp index 5b5e859689..82ca50411a 100644 --- a/modules/core/src/parallel.cpp +++ b/modules/core/src/parallel.cpp @@ -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 // 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 {