tutorialspoint threads thread multithread c++ exception signals

c++ - threads - Lanzar una excepción desde dentro de un manejador de señal



tutorialspoint c++ thread (5)

Tenemos una biblioteca que trata muchos aspectos de la notificación de errores. Me han asignado la tarea de portar esta biblioteca a Linux. Cuando se ejecuta a través de mi pequeño conjunto de pruebas, una de las pruebas falló. Una versión simplificada de la prueba aparece a continuación.

// Compiler: 4.1.1 20070105 RedHat 4.1.1-52 // Output: Terminate called after throwing an instance of ''int'' abort #include <iostream> #include <csignal> using namespace std; void catch_signal(int signalNumber) { signal(SIGINT, SIG_DFL); throw(signalNumber); } int test_signal() { signal(SIGINT, catch_signal); try { raise(SIGINT); } catch (int &z) { cerr << "Caught exception: " << z << endl; } return 0; } int main() { try { test_signal(); } catch (int &z) { cerr << "Caught unexpected exception: " << z << endl; } return 0; }

Mi expectativa es que se muestre el mensaje Excepción capturada: Lo que realmente sucede es que el programa termina ya que no parece que haya un controlador de captura presente para el int lanzado.

Hay algunas preguntas sobre SO que parecen relacionadas. Encontré varias páginas de Google que estaban relacionadas. La ''sabiduría'' parece reducirse a

  1. Ya no puede lanzar excepciones de los manejadores de señales, ya que el manejador de señales se ejecuta con su propia pila, por lo que no hay manejadores definidos en ella.
  2. Ya puedes lanzar excepciones de los manejadores de señales, solo reconstruye un marco falso en la pila y listo.
  3. Ya lo hacemos todo el tiempo. Funciona para mí en la plataforma X
  4. Ya, eso solía estar disponible con gcc, pero parece que ya no funciona. Pruebe la opción -fnon-call-exceptions , tal vez eso funcione

    El código funciona como se espera en nuestro compilador / entornos AIX / TRU64 / MSVC. Falla en nuestro entorno Linux.


Estoy buscando sugerencias para ayudar a resolver este problema para que el comportamiento de la biblioteca en Linux coincida con mis otras plataformas, o algún tipo de solución que pueda lograr el mismo tipo de funcionalidad.
Dejar que el programa descargue la señal, no es una opción viable.


Enmascararía todas las señales en todos los hilos, excepto uno que esperaría señales con sigwait () . Este hilo puede manejar señales sin restricción, por ejemplo, lanzar excepciones o usar otros mecanismos de comunicación.


Este código demuestra una técnica que mueve el lanzamiento de la excepción del manejador de señales al código. Mi agradecimiento a Charles por la idea.

#include <iostream> #include <csignal> #include <csetjmp> using namespace std; jmp_buf gBuffer; // A buffer to hold info on where to jump to void catch_signal(int signalNumber) { //signal(SIGINT, SIG_DFL); // Switch to default handling signal(SIGINT, catch_signal); // Reactivate this handler. longjmp // Jump back into the normal flow of the program ( gBuffer, // using this context to say where to jump to signalNumber // and passing back the value of the signal. ); } int test_signal() { signal(SIGINT, catch_signal); try { int sig; if ((sig = setjmp(gBuffer)) == 0) { cout << "before raise/n"; raise(SIGINT); cout << "after raise/n"; } else { // This path implies that a signal was thrown, and // that the setjmp function returned the signal // which puts use at this point. // Now that we are out of the signal handler it is // normally safe to throw what ever sort of exception we want. throw(sig); } } catch (int &z) { cerr << "Caught exception: " << z << endl; } return 0; } int main() { try { test_signal(); } catch (int &z) { cerr << "Caught unexpected exception: " << z << endl; } return 0; }


Las señales son totalmente diferentes a las excepciones de C ++. No puede usar un bloque de prueba / captura de C ++ para manejar una señal. Específicamente, las señales son un concepto POSIX, no un concepto de lenguaje C ++. Las señales se envían de forma asíncrona a su aplicación por parte del kernel, mientras que las excepciones de C ++ son eventos síncronos definidos por el estándar de C ++.

Usted está bastante limitado en lo que puede hacer de manera portátil en un controlador de señales POSIX. Una estrategia común es tener un indicador global de tipo sig_atomic_t que se establecerá en 1 en el controlador de señal, y luego posiblemente longjmp a la ruta de ejecución adecuada.

Consulte here para obtener ayuda para escribir los manejadores de señales adecuados.


Probablemente no sea una buena idea deshacerse de un controlador de señales, ya que la pila no está necesariamente configurada de la misma manera que para las llamadas de función, por lo que el desenrollado de un controlador de señales puede no funcionar como se espera.

Se debe tomar nota importante para cualquier registro utilizado por la ABI de C ++ que se guarde y reutilice por el mecanismo de manejo de señales.


opción google g ++

-fnon-call-exceptions

Esto es esencialmente lo que quieres. Creo que esto fue desarrollado debido a la presión de Apple para su sistema operativo. No estoy seguro de cómo está soportado en LINUX. Y no estoy seguro si uno puede detectar SIGINT, pero todas las señales activadas por la CPU (aeh excepciones) pueden detectarse. Los codificadores que necesitan esta función (y no se preocupan por la ideología) deberían ejercer cierta presión sobre la comunidad de desarrolladores de LINUX para que también sea compatible con LINUX algún día, después de haber recibido soporte en Windows desde hace casi dos décadas.