2008-10-08 5 views
5

Avant de commencer, je tiens à préciser qu'il ne s'agit pas d'un outil de ligne de commande, mais d'une application qui accepte les commandes via sa propre interface de ligne de commande.Comment gérer un signal ctrl-break dans une interface de ligne de commande

Editer: Je dois m'excuser de mon explication d'avant, apparemment je n'ai pas fait un très bon travail pour l'expliquer. Une fois de plus ...

Je construis une application d'interface de ligne de commande qui accepte les commandes d'un utilisateur. J'ai une configuration de gestionnaire de signal pour attraper les signaux, qui définit ensuite un drapeau dont j'ai besoin pour terminer l'application. Le problème que je rencontre est que toutes les fonctions de la console que je peux trouver bloquent, ce qui signifie que je ne peux pas détecter que j'ai besoin de quitter la boucle de traitement de la console jusqu'à ce que l'utilisateur appuie sur une touche). Existe-t-il une manière standard de faire une interaction avec une console non-block, ou existe-t-il un moyen élégant de structurer le programme de sorte que si je viens de terminer le thread de signal, tout sera traité et libéré correctement ne comprenez pas cela, je sais comment cela pourrait être fait en verrouillant et libérant les ressources du fil de signalisation, mais cela pourrait devenir salissant, donc je préfère l'éviter)

Espérons que cette explication a plus de sens ...

Répondre

6

Sur * nix, vous pouvez utilisez la fonction signal pour enregistrer un gestionnaire de signal:


#include <signal.h> 

void signal_handler(int sig) 
{ 
    // Handle the signal 
} 

int main(void) 
{ 
    // Register the signal handler for the SIGINT signal (Ctrl+C) 
    signal(SIGINT, signal_handler); 
    ... 
} 

Maintenant, chaque fois que quelqu'un touche Ctrl + C, votre gestionnaire de signal sera appelé.

0

Sur un système basé sur * nix, vous n'avez pas vraiment besoin d'un gestionnaire de signal pour que cela fonctionne. Vous pouvez spécifier que vous voulez ignorer l'appel SIGINT

int main(void) 
{ 
    // Register to ignore the SIGINT signal (Ctrl+C) 
    signal(SIGINT, SIG_IGN); 

    while(1) 
    { 
    retval = my_blocking_io_func(); 
    if(retval == -1 && errno == EINTR) 
    { 
     // do whatever you want to do in case of interrupt 
    } 
    } 
} 

Le moyen important que cela fonctionne est de reconnaître que les fonctions non-blocage obtiennent interrompu. Normalement, vous vous rendez compte que la fonction de blocage a échoué (par exemple read()) et réessayez la fonction. Si c'était une autre valeur, vous prendriez l'action appropriée liée à l'erreur.

8

OK - cela fonctionne pour moi sur Windows & est portable - notez le #ifdef SIGBREAK - ce n'est pas un signal standard.

#include <csignal> 
#include <iostream> 
#include <ostream> 
#include <string> 
using namespace std; 

namespace 
{ 
    volatile sig_atomic_t quit; 

    void signal_handler(int sig) 
    { 
     signal(sig, signal_handler); 
     quit = 1; 
    } 
} 

int main() 
{ 
    signal(SIGINT, signal_handler); 
    signal(SIGTERM, signal_handler); 
#ifdef SIGBREAK 
    signal(SIGBREAK, signal_handler); 
#endif 
    /* etc */ 

    while (!quit) 
    { 
     string s; 
     cin >> s; 
     cout << s << endl; 
    } 
    cout << "quit = " << quit << endl; 
} 
+1

Remarque: sous Windows, cliquez sur le bouton Fermer soulèvera le code sig 'SIGBREAK' (ctrl Pause) – 56ka

0

Une meilleure solution * nix qui est thread-safe est d'utiliser pthread_sigmask() au lieu de signal().
Par exemple, voici comment vous signore SIGINT, SIGTERM et SIGPIPE dans le thread actuel et futur a donné naissance à des fils:

sigset_t waitset; 
sigemptyset(&waitset); 
sigaddset(&waitset, SIGINT); 
sigaddset(&waitset, SIGTERM); 
sigaddset(&waitset, SIGPIPE); 
pthread_sigmask(SIG_BLOCK, &waitset, NULL); 
Questions connexes