2012-08-06 115 views
6

OpenMP禁止通過異常離開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(); } 
} 

雖然這工作得很好,只要ThreadException對象被銷燬從並行段重新拋出可能的例外,這個結構仍然是一個有點笨拙的用於在每個部分周圍放置一個try {}catch(...){},並且不得不手動捕獲異常。

所以我的問題是:有沒有人知道一個更優雅(不太詳細)的方式來做到這一點(如果是這樣,它是什麼樣子)?

+0

你會如何處理的情況下,當兩個或多個線程拋出異常(可能不同的)? – 2012-08-06 13:04:57

+0

@HristoIliev:忽略其中的一個(因爲我不能拋出更多的異常),並且只能重新拋出最後一個。 – Grizzly 2012-08-06 13:13:33

+0

從析構函數中拋出是非法的(我曾經使用過一個這樣做過的庫,它給我帶來了很多頭痛,直到我找出爲什麼我的應用程序不停地捕捉異常)。你必須在parallel部分之後調用'except.Rethrow()'。如果在並行部分之後有順序代碼,如果發生異常時您不想執行,那麼這將會更好。 – 2017-08-29 22:14:21

回答

8

您可以利用更多的C++ 11工具來清理語法。一個OpenMP構造內打電話時

class ThreadException { 

    // ... 

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

然後使用lambda函數像這樣:這個參數可變成員函數添加到您的ThreadException

ThreadException e; 

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

由於一些奇怪的原因,我沒有考慮將函數傳遞給Exception類,所以感謝您的建議。 – Grizzly 2012-12-21 12:45:45

+1

另外,從析構函數調用Rethrow()時要小心 - 這會崩潰並燒壞! – 2012-12-21 19:28:11