2011-10-01 13 views
12

Si suppone di ignorare il segnale CtrlC e usarlo per stampare un messaggio. Non dovrebbe terminare il programma.Override Ctrl-C

Cosa accade finora è che quando viene premuto Ctrl C stampa il messaggio, ma termina il programma.

Quando ho chiesto al mio professore mi ha detto di farlo: È necessario impedire al gestore del segnale di continuare a elaborare il segnale. In questo momento il segnale viene gestito dal tuo codice e quindi passa al gestore principale.

C'è un metodo che dovrei aggiungere o devo spostare gli installatori di segnale da qualche parte?

Questo è il mio codice finora:

#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

NON chiamare "printf' dall'interno di un gestore di segnale perché" printf' non è async-safe. Vedi 'segnale uomo 7' per un elenco di funzioni sicure asincrone. Il più semplice syscall 'write' è async safe, ma nessuna delle funzioni' '' è. –

risposta

10

Whoa, modo troppo codice di passare al setaccio. Tuttavia, se si utilizza la libreria standard C, si dovrebbe ottenere il comportamento desiderato. Ecco una versione 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; } 
    } 
} 

Questa cattura Ctrl-C (che solleva SIGINT), e il gestore di segnale non viene sostituito, in modo che sarà fuoco ogni volta, e nessuno sta terminando il programma.

Nota che i gestori di segnale sono ereditati dai bambini fork().

La funzione Posix sigaction() consente di registrare gestori "one-shot" che vengono sostituiti dal gestore standard dopo che sono stati richiamati una volta. Questo è più avanzato e specifico per Posix, però.

Edit: Come @Dietrich fa notare, non si dovrebbe mai fare alcun vero lavoro all'interno un gestore di segnale. Piuttosto, dovresti impostare un flag (ho fornito un esempio) e controllare quel flag all'interno del tuo loop (e stampare il messaggio lì). Modificheremo anche l'esempio per quello.

+0

È * molto pericoloso * usare 'std :: cerr' all'interno di un gestore di segnale. –

+0

@DietrichEpp: non sicuro o imprevedibile? Qual è la cosa peggiore che potrebbe accadere? Sicuramente la cosa giusta da fare è impostare una bandiera e andare avanti, ma questo complicherebbe l'esempio. Prenderò un appunto, comunque. –

+0

grazie per l'input. Proverò questa opzione, sfortunatamente il professore vuole che noi gestiamo i segnali usando i metodi c. (Ho anche accorciato il codice per includere solo il materiale importante) – ensantos91

0

Avete considerato che all'interno del vostro ciclo while potrebbe esserci una funzione interrompibile in mancanza di "EINTR". Si potrebbe potrebbe essere in grado di risolvere il problema utilizzando:

sa.sa_flags = SA_RESTART; 

Oppure, semplicemente controllando errno per esso e loop. Sei sicuro che il programma non stia raggiungendo la fine della risoluzione. Prova a inserire una dichiarazione di stampa alla fine del main.