2011-10-01 12 views
12

supone que tengo anular el CtrlC señal y lo utilizan para imprimir un mensaje. No se supone que termine el programa.Invalidar Ctrl-C

¿Qué ocurre hasta ahora es que cuando se pulsa Ctrl C imprime el mensaje, pero que termine el programa.

Cuando le pregunté a mi profesor me dijo que hiciera esto: Necesita hacer que su manejador de señal evite continuar procesando la señal. En este momento, la señal está siendo manejada por su código y luego pasando al controlador principal.

¿Hay algún método que deba agregar o necesito mover los instaladores de señal en algún lugar?

Este es mi código hasta ahora:

#include <stdio.h> 
#include <unistd.h> 
#include <sys/wait.h> 
#include <sys/types.h> 
#include <signal.h> 
#include "Input.h" 
#include "CircleBuff.h" 

//void handler_function(int signal_id); 

void catch_int(int sig_num){ 

    //reset the signal handler again to catch_int, for next time 
    signal(SIGINT, catch_int); 
    //print message 
    printf("Print History"); 
    fflush(stdout); 
} 

void printHistory(CircleBuff hist){ 
    cout << "Complete History:\n" << endl; 
    hist.print(); 
    cout << endl; 
} 

int main(int argc, char** argv){ 

    struct sigaction signal_action;    /* define table */ 
    signal_action.sa_handler = catch_int; /* insert handler function */ 
    signal_action.sa_flags = 0;     /* init the flags field */ 
    sigemptyset(&signal_action.sa_mask);  /* are no masked interrupts */ 
    sigaction(SIGINT, &signal_action, NULL); /* install the signal_action */ 

    do{ 


    //My code: where the value report will be assigned within. 

    } while(report != 1) 

} 
+0

NO debe llamar a 'printf' desde dentro de un manejador de señal porque' printf' no es asincrónico. Ver 'man 7 signal' para una lista de funciones async-safe. La llamada más simple de 'write' es asíncrona segura, pero ninguna de las funciones '' son. –

Respuesta

10

Whoa, manera demasiado código para tamizar a través. Sin embargo, si usa la biblioteca estándar C, debe obtener el comportamiento deseado. He aquí una versión de C++:

#include <iostream> 
#include <csignal> 

sig_atomic_t sigflag = 0; 

void sighandler(int s) 
{ 
    // std::cerr << "Caught signal " << s << ".\n"; // this is undefined behaviour 
    sigflag = 1; // something like that 
} 

int main() 
{ 
    std::signal(SIGINT, sighandler); 

    // ... your program here ... 

    // example: baby's first loop (Ctrl-D to end) 
    char c; 
    while (std::cin >> c) 
    { 
    if (sigflag != 0) { std::cerr << "Signal!\n"; sigflag = 0; } 
    } 
} 

Esto cogerá Ctrl-C (lo que plantea SIGINT), y el manejador de la señal no se reemplaza, por lo que va a disparar cada vez, y nadie se da por concluido el programa.

Tenga en cuenta que los controladores de señal son heredados por fork() ed children.

La función de Posix sigaction() le permite registrar manejadores "one-shot" que son reemplazados por el manejador estándar después de ser invocados una vez. Sin embargo, eso es más avanzado y específico de Posix.

Editar: Como @Dietrich señala, que nunca debe hacer ningún trabajo real dentro un manejador de señales. Por el contrario, debe establecer una bandera (proporcioné un ejemplo), y buscar esa bandera dentro de su bucle (e imprimir el mensaje allí). Voy a enmendar el ejemplo para eso también.

+0

Es * muy inseguro * usar 'std :: cerr' dentro de un manejador de señal. –

+0

@DietrichEpp: ¿Inseguro o impredecible? ¿Que es lo peor que puede pasar? Seguramente lo correcto es establecer una bandera y seguir adelante, pero eso complicaría el ejemplo. Haré una nota, sin embargo. –

+0

gracias por su aporte. Voy a probar esa opción, desafortunadamente el profesor quiere que manejemos señales usando métodos c. (también acorté el código para incluir solo el material importante) – ensantos91

0

¿Ha considerado que dentro de su ciclo while puede haber una función interrumpible que falla con 'EINTR'. Podría solucionarlo utilizando:

sa.sa_flags = SA_RESTART; 

O, simplemente revisando errno y bucles. ¿Estás seguro de que el programa no está llegando al final de la finalización? Intenta poner una declaración impresa al final de la página principal.