在OpenMP中优雅的异常处理

Gri*_*zly 8 c++ exception-handling openmp c++11

OpenMP禁止通过异常离开openmp块的代码.因此,我正在寻找一种从openmp块获取异常的好方法,目的是在主线程中重新抛出它并在稍后处理.到目前为止,我能够提出的最好的是以下内容:

class ThreadException {
    std::exception_ptr Ptr;
    std::mutex         Lock;
public:
    ThreadException(): Ptr(nullptr) {}
    ~ThreadException(){ this->Rethrow(); }  
    void Rethrow(){
        if(this->Ptr) std::rethrow_exception(this->Ptr);
    }
    void CaptureException() { 
        std::unique_lock<std::mutex> guard(this->Lock);
        this->Ptr = std::current_exception(); 
    }   
};
//...
ThreadException except;
#pragma omp parallel
{
    try {
      //some possibly throwing code
    } 
    catch(...) { except.CaptureException(); }
}
Run Code Online (Sandbox Code Playgroud)

虽然这很好用,但是一旦ThreadException对象被销毁,就可以从并行部分重新抛出可能的异常,这个结构仍然有点笨拙用于放置try {}catch(...){}每个部分并且必须手动捕获异常.

所以我的问题是:有没有人知道更优雅(更简洁)的方式(如果是这样,它看起来像什么)?

Kyl*_*oli 10

您可以使用更多的C++ 11工具来清理语法.将此可变参数成员函数添加到您的ThreadException类:

class ThreadException {

    // ...

    template <typename Function, typename... Parameters>
    void Run(Function f, Parameters... params)
    {
        try 
        {
            f(params...);
        }
        catch (...)
        {
            CaptureException();
        }
    }
 };
Run Code Online (Sandbox Code Playgroud)

然后在OpenMP构造内部调用时使用lambda函数,如下所示:

ThreadException e;

#pragma omp parallel for
for (int i = 0; i < n; i++)
{
    e.Run([=]{
        // code that might throw
        // ...
    });
}
e.Rethrow()
Run Code Online (Sandbox Code Playgroud)

  • 另外,要小心从析构函数中调用Rethrow() - 这会导致崩溃和严重烧伤! (3认同)