2012-08-06 8 views
6

OpenMP prohíbe el código que deja el bloque de openmp por excepción. Por lo tanto, estoy buscando una buena manera de obtener las excepciones de un bloque openmp con el propósito de volver a lanzarlo en el hilo principal y manejarlo en un momento posterior. Hasta ahora el mejor que he podido para llegar a es el siguiente:Elegante manejo de excepción en 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(); } 
} 

Aunque esto funciona muy bien, Regeneración de las posibles excepciones de la sección paralela, tan pronto como el objeto ThreadException se destruye, esta construcción sigue siendo una Es un poco difícil de usar al colocar un try {}catch(...){} alrededor de cada sección y tener que capturar manualmente la excepción.

Así que mi pregunta es: ¿Alguien sabe de una manera más elegante (menos detallada) para hacer esto (y si es así, cómo se ve)?

+0

¿Cómo manejaría el caso de que dos o más hilos que generan excepciones (posiblemente diferentes)? –

+0

@HristoIliev: Ignorando uno de ellos (ya que no puedo arrojar más de una excepción) y solo volviendo a lanzar el último. – Grizzly

+0

Lanzar desde un destructor es ilegal (he usado una biblioteca que hizo esto, y me provocó muchos dolores de cabeza hasta que descubrí por qué mi aplicación seguía abortando sin detectar la excepción). Tendría que llamar a 'except.Rethrow()' después de la sección paralela. Esto sería mejor de cualquier forma si hay un código secuencial después de la sección paralela que no desea ejecutar si se produce una excepción. –

Respuesta

8

Puede utilizar algunas herramientas C++ 11 para limpiar un poco la sintaxis. Añadir esta función de miembro variadic a su clase ThreadException:

class ThreadException { 

    // ... 

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

A continuación, al llamar dentro de un constructo OpenMP utilizar una función lambda, así:

ThreadException e; 

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

Por algún extraño motivo, no había considerado pasar un funtor a la clase Excepción, así que gracias por la sugerencia. – Grizzly

+1

Además, tenga cuidado con esa llamada a Rethrow() del destructor: ¡se bloqueará y se quemará mal! –

Cuestiones relacionadas