2016-06-04 1 views
1

Je dois exécuter des fonctions de nettoyage dans le gestionnaire SIGINT, mais je ne peux pas lui transmettre de données locales. Voici un exemple:Comment nettoyer les données locales dans le gestionnaire SIGINT

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

    struct database *db = db_cursor(); 
    sockfd_t master_socket = init_server(); 

    signal(SIGINT, sigint_handler); 

    while (1) { 
     // accepting connections 
    } 
} 

void sigint_handler(int s) { 
    destroy_db(db); 
    shutdown(master_socket, SHUT_RDWR); 
    close(master_socket); 
    exit(EXIT_SUCCESS); 
} 

Comment puis-je implémenter un tel comportement? J'ai essayé de rendre ces variables globales, mais Je ne peux pas appeler cette fonction au moment de la compilation (erreur: l'élément initializer n'est pas une constante de compilation).

+3

Vous ne devriez pas faire tout cette logique dans le gestionnaire lui-même. Ayez juste un drapeau et testez le drapeau dans la boucle principale. –

+0

Ajout au commentaire d'Oliver: Tapez le drapeau 'sig_atomic_t'. – alk

+0

Maintenant cela fonctionne, mais j'ai des appels bloquants comme 'accept', et quand j'appelle' SIGINT' il ne s'arrête pas immédiatement. Devrais-je utiliser le multiplexage pour résoudre ce problème? – 0x1337

Répondre

3

Seul un nombre très limité de fonctions est garanti pour un signal asynchrone sécurisé et peut donc être appelé depuis un gestionnaire de signaux, exit() f.e. ne leur appartient pas.

une approche différente:

#include <signal.h> 

volatile sig_atomic_t sigint_received = 0; /* volatile might be necessary depending on 
               the system/implementation in use. 
               (see "C11 draft standard n1570: 5.1.2.3")*/ 

void sigint_handler(int s) 
{ 
    sigint_received = 1; 
} 

int main(void) 
{ 
    signal(SIGINT, sigint_handler); 

    while (!sigint_received) 
    { 
    /* Do stuff. */ 
    } 

    /* Clean up here. */ 
} 

Pour en savoir plus sur ce sujet, voir


Remarque: Pour être portable maximum, vous souhaitez utiliser sigaction() au lieu de signal().

Le code pour remplacer signal() pourrait ressembler à ceci:

struct sigaction sa = 
{ 
    sigint_handler 
    /*, SA_RESTART */ /* Set this by if blocking calls like read() or accept() 
         should _not_ return on signal reception. */ 
}; 

if (-1 == sigaction(SIGINT, &sa, NULL)) 
{ 
    perror("sigaction() failed"); 
    exit(EXIT_FAILURE); 
} 

Documentation sur sigaction():

+1

'volatile sig_atomic_t'. – EOF

+0

Non. Pourquoi pensez-vous que cela est nécessaire? @EOF – alk

+0

La disposition du signal se fait via l'OS * vers * le processus. Aucun périphérique externe ne change quoi que ce soit ici. – alk