En el siguiente código:

#include <unistd.h>
#include<iostream>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
using namespace std;
void signal_callback_handler(int signum)

{
printf ("Caught signal %d\n", signum);
exit (signum);
}

int main()
{
signal (SIGFPE, signal_callback_handler);

int a=4;
int b=55444;

while (1)
{
printf ("Program processing stuff here.\n");
cout<<b/a;
a--;
b++;
sleep (1);
}
return EXIT_SUCCESS;
}

Cuando la variable 'a' se convierte en 0, el programa obtiene la señal SIGFPE del sistema operativo y el programa termina con el mensaje: "Señal capturada 8". Sin embargo, si comento, la "salida (signum)"; línea en la definición 'signal_callback_handler', el programa sigue ejecutándose sin cesar y sigue imprimiendo la declaración "Caught Signal 8" en la pantalla. ¿Por qué pasó esto? ¿Por qué esta señal se genera de alguna manera repetidamente?

Esperaba que la señal se generara una vez, y después de pasar por la función de controlador de señal, el programa se reanudará después de la declaración 'cout << b / a' y luego el programa continuará normalmente. Sin embargo, dado que esto no está sucediendo , ¿cómo puedo lograr mi objetivo?

1
Vishal Sharma 3 mar. 2018 a las 11:21

3 respuestas

La mejor respuesta

En x86, esto se debe a que el error de división es una falla , lo que significa cuando el flujo de control regresa, el contador del programa (%rip) señalará la dirección del código defectuoso anterior, no la siguiente instrucción.

Una estrategia normal de manejar SIGFPE es utilizar setjmp para saltar a un estado recuperable desde el controlador de señal.

Un ejemplo simple de su propio código (por cierto, nunca use printf() en el controlador de señal):

#include <setjmp.h>
using namespace std;

jmp_buf excep;

void signal_callback_handler(int signum)

{
longjmp(excep, 1);
}

int main()
{
signal (SIGFPE, signal_callback_handler);

int a=4;
int b=55444;

    while (1)
    {
        printf ("Program processing stuff here.\n");
        if ( setjmp(excep) == 0 ) {
            // normal control flow
            cout<<b/a;
        }
        else {
            // from longjmp
            printf("Exception caught\n");
        }
        a--;
        b++;
        sleep (1);
    }
return EXIT_SUCCESS;
}
1
llllllllll 3 mar. 2018 a las 09:12

Se recomienda para señales como SIGILL o SIGFPE para detener la ejecución y no intentar recuperar.

POSIX dice:

El comportamiento de un proceso no está definido después de que vuelve normalmente de una función de captura de señal para una señal SIGBUS, SIGFPE, SIGILL o SIGSEGV que no fue generada por kill (), sigqueue () o raise ().

En muchas implementaciones, cuando el controlador finaliza, la instrucción que generó la excepción se reinicia, lo que generó un nuevo SIGFPE, etc.

1
Jean-Baptiste Yunès 3 mar. 2018 a las 08:31

Creo que gcc crea un punto de retorno en el bucle while para usted desde el controlador de señal y sigue entrando y saliendo del controlador de señal. Puede intentar usar el atributo no_return para gcc para asegurarse de que su programa no regrese al ciclo while y puede continuar su programa llamando a alguna otra función.

1
BunnyDhaliwal 3 mar. 2018 a las 08:30