2012-08-06 8 views
6

OpenMP zabrania kodu, który opuszcza blok OpenMP przez wyjątek. Dlatego szukam ładnego sposobu na uzyskanie wyjątków z bloku OpenMP w celu ponownego wrzucenia go w główny wątek i obsługi w późniejszym czasie. Do tej pory najlepszy byłem w stanie wymyślić, to:Elegant exceptionhandling w 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(); } 
} 

Chociaż to działa dobrze, Ponowne generowanie możliwych wyjątków z sekcji równoległej jak tylko obiekt ThreadException jest zniszczony, konstrukcja ta jest nadal Trochę niezręczny w użyciu przy wstawianiu try {}catch(...){} wokół każdej sekcji i konieczności ręcznego przechwytywania wyjątku.

Moje pytanie brzmi: czy ktokolwiek zna bardziej elegancki (mniej gadatliwy) sposób na zrobienie tego (a jeśli tak, jak to wygląda)?

+0

W jaki sposób można obsłużyć przypadek, gdy dwa lub więcej wątków rzucać wyjątki (możliwe inne)? –

+0

@HristoIliev: Ignorując jednego z nich (ponieważ nie mogę wyrzucić ani jednego wyjątku) i tylko ponownie wyrzucając ostatnią. – Grizzly

+0

Rzucanie z destruktora jest nielegalne (użyłem biblioteki, która to zrobiła i spowodowało to wiele bólów głowy, dopóki nie zorientowałem się, dlaczego moja aplikacja ciągle przerywa, nie wychwytując wyjątku). Będziesz musiał wywołać 'except.Rethrow()' po sekcji równoległej. Byłoby lepiej w każdym przypadku, gdyby po sekcji równoległej był kod sekwencyjny, którego nie chcesz wykonywać, jeśli wystąpił wyjątek. –

Odpowiedz

8

Możesz użyć kilku dodatkowych narzędzi w C++ 11, aby nieco wyczyścić składnię. Dodaj zmiennej liczbie argumentów funkcji członka do klasy ThreadException:

class ThreadException { 

    // ... 

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

następnie, gdy dzwoni wewnątrz konstruktu OpenMP użyć funkcji lambda tak:

ThreadException e; 

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

Z jakiegoś dziwnego powodu nie rozważałem przejścia funktora do klasy Wyjątek, więc dziękuję za sugestię. – Grizzly

+1

Należy również zachować ostrożność przy wywołaniu funkcji Rethrow() z destruktora - to się zawiesi i zacznie płonąć! –