2008-11-30 16 views

Respuesta

4

Creo que el estándar C++ no menciona el multihilo: el multihilo es una característica específica de la plataforma.

No estoy exactamente seguro de lo que dice el estándar C++ sobre excepciones no detectadas en general, pero de acuerdo con this page, lo que ocurre es definición de plataforma, y ​​debe encontrarlo en la documentación del compilador.

En una prueba rápida y sucia hice con g ++ 4.0.1 (i686-apple-darwin8-g ++ - 4.0.1 para ser específico), el resultado es que se llama terminate(), lo que mata a todo el programa. El código utilicé la siguiente manera:

#include <stdio.h> 
#include <pthread.h> 

void *threadproc(void *x) 
{ 
    throw 0; 

    return NULL; 
} 

int main(int argc, char **argv) 
{ 
    pthread_t t; 
    pthread_create(&t, NULL, threadproc, NULL); 

    void *ret; 
    pthread_join(t, &ret); 

    printf("ret = 0x%08x\n", ret); 

    return 0; 
} 

compilado con g++ threadtest.cc -lpthread -o threadtest. La salida fue:

terminate called after throwing an instance of 'int' 
+0

Iba a escribir lo mismo. Simplemente deje en claro que la aplicación terminará (alguien puede interpretar que solo el hilo se acaba con terminación). terminate() hará que todos los hilos se eliminen sin que se produzca ningún otro procesamiento. –

+0

PD. Este es el comportamiento de todas las bibliotecas pthread que he usado. –

0

No recomiendo dejar ninguna excepción sin capturar. Envuelva las funciones de subproceso de nivel superior en controladores de catch-all que pueden cerrar el programa de forma más elegante (o al menos exhaustiva).

+0

Aunque esto * puede * tener sentido para algunas aplicaciones, no estoy de acuerdo con él como consejo general. Por lo general, recomiendo que las personas manejen las excepciones cuando tenga sentido, de lo contrario, que se propaguen. Si usó RAII correctamente, apagarlo no debería ser un problema. – MattyT

+0

Excepto que sus destructores de RAII pueden no ser llamados si la excepción no se detecta. Depende de la implementación si una excepción no detectada desenrolla la pila o no. Simplemente puede abortar. Si atrapas todo en la parte superior, garantizas que la pila se desenrolla. –

+0

@onebyone: ¿Según qué párrafo de la especificación? Solo quiero saber que todos los gurús de C++ (Herb Sutter, etc.) recomiendan escribir código que no use try/catch, sino que sea "exception-agnostic". –

0

Creo que lo más importante es recordar que las excepciones no detectadas de otros hilos no se muestran al usuario o se lanzan al hilo principal. Entonces, debe urdir todo el código que debe ejecutarse en hilos diferentes al hilo principal con los bloques try/catch.

2

Una excepción no detectada llamará al terminate() que a su vez llama al terminate_handler (que puede ser configurado por el programa). Por defecto, el terminate_handler llama al abort().

Incluso si anula el valor predeterminado terminate_handler, la norma dice que la rutina que proporcione "terminará la ejecución del programa sin regresar a la persona que llama" (ISO 14882-2003 18.6.1.3).

Por lo tanto, en resumen, una excepción no detectada terminará el programa, no solo el hilo.

En lo que respecta a la seguridad de los hilos, como dice Adam Rosenfield, esta es una cuestión específica de la plataforma que no se aborda en el estándar.

2

Esta es la principal razón por la que existe Erlang.

No sé cuál es la convención, pero en mi humilde opinión, sé lo más parecido posible a Erlang. Haga que los objetos de montón sean inmutables y configure algún tipo de protocolo de paso de mensajes para comunicarse entre hilos. Evita los bloqueos. Asegúrese de que el mensaje que pasa sea a prueba de excepciones. Mantenga tantas cosas con estado en la pila.

2

Como han discutido otros, la concurrencia (y la seguridad de subprocesos en particular) es un problema arquitectónico que afecta la forma en que diseña su sistema y su aplicación.

Pero me gustaría responder a su pregunta sobre la tensión entre excepción-seguridad e hilo de seguridad.

En el nivel de clase, la seguridad de los hilos requiere cambios en la interfaz. Al igual que la excepción, la seguridad sí.Por ejemplo, es habitual que las clases para volver referencias a variables internas, por ejemplo:

class Foo { 
public: 
    void set_value(std::string const & s); 

    std::string const & value() const; 
}; 

Si Foo es compartida por múltiples hilos, problemas le espera. Naturalmente, podría poner un mutex u otro bloqueo para acceder a Foo. Pero pronto, todos los programadores de C++ querrían envolver a Foo en un "ThreadSafeFoo". Mi opinión, es que la interfaz de Foo debe ser cambiado a:

class Foo { 
public: 
    void set_value(std::string const & s); 

    std::string value() const; 
}; 

Sí, es más caro, pero se puede hacer seguro para subprocesos con las cerraduras dentro de Foo. IMnsHO esto crea una cierta cantidad de tensión entre la seguridad de la rosca y la seguridad de la excepción. O al menos, necesita realizar más análisis ya que cada clase utilizada como recurso compartido debe examinarse bajo ambas luces.

1

Hay dos cuestiones que me di cuenta:

  • en g ++ en Linux, el asesinato de un hilo (pthread_cancel) se realiza mediante una excepción "desconocido". Por un lado, eso te permite limpiar bien cuando se está matando el hilo. Por otro lado, si detecta esa excepción y no la vuelve a lanzar, su código termina con abort(). Por lo tanto, si usted o cualquiera de las bibliotecas que utiliza hilos de matar, no se puede tener

    captura (...)

sin

throw; 

en el código roscado. Here es una referencia a este comportamiento en la web:

  • A veces es necesario transferir la excepción entre subprocesos. Esto no es algo fácil de hacer, terminamos haciendo algo, cuando la solución adecuada es el tipo de marshalling/demarshalling que usarías entre los procesos.
7

C++ 0x tendrá Language Support for Transporting Exceptions between Threads de modo que cuando un hilo de trabajo arroje una excepción, el hilo de desove pueda atraparlo o volver a lanzarlo.

partir de la propuesta:

namespace std { 

    typedef unspecified exception_ptr; 

    exception_ptr current_exception(); 
    void rethrow_exception(exception_ptr p); 

    template< class E > exception_ptr copy_exception(E e); 
} 
+2

Tenga en cuenta que esta funcionalidad ya existe en boost. –

+1

Para obtener más información sobre la implementación de Boost: http://www.boost.org/doc/libs/release/libs/exception/doc/tutorial_exception_ptr.html –

2

Un ejemplo clásico (no recuerdo donde vi por primera vez) se encuentra en la biblioteca std.

Así es como usted hace estallar algo de una cola:

T t; 
t = q.front(); // may throw 
q.pop(); 

Esta interfaz es algo obtuso en comparación con:

T t = q.pop(); 

Pero se hace porque la asignación copia T puede lanzar. Si la copia se lanza después de que ocurre el pop, ese elemento se pierde de la cola y nunca se puede recuperar. Pero dado que la copia ocurre antes de que el elemento aparezca, puede poner un manejo arbitrario alrededor de la copia desde el frente() en los bloques try/catch.

La desventaja es que no puede implementar una cola segura para subprocesos con la interfaz de std :: queue debido a los dos pasos implicados. Lo que es bueno para la seguridad de excepciones (separar los pasos que se pueden lanzar), ahora es malo para el multihilo.

Su salvador principal en cuanto a la seguridad de las excepciones es que las operaciones del puntero no son de tiro. De forma similar, las operaciones de puntero se pueden hacer atómicas en la mayoría de las plataformas, por lo que a menudo pueden ser su salvador en código multiproceso. Puedes tener tu pastel y comértelo también, pero es muy difícil.

+0

No entendí cómo concluyó "no se puede implementar una cola que es seguro para subprocesos con la interfaz de std :: queue debido a los dos pasos involucrados ". –

+1

Piénselo: incluso si bloquea el acceso a la estructura de datos interna, porque ese bloqueo no se mantiene entre las llamadas al frente y al pop, después de obtener el elemento frontal, otro hilo también podría obtener el mismo elemento frontal antes que usted Apagarlo, luego pierde un elemento y un elemento se duplica. –

Cuestiones relacionadas