2008-10-08 10 views
5

Antes de comenzar, quiero aclarar que esta no es una herramienta de línea de comandos, sino una aplicación que acepta comandos a través de su propia interfaz de línea de comandos.Cómo manejar una señal ctrl-break en una interfaz de línea de comandos

Edición: Debo pedir disculpas por mi explicación de antes, aparentemente no hice un muy buen trabajo al explicarla. Una vez más ...

Estoy construyendo una aplicación de interfaz de línea de comandos que acepta comandos de un usuario. Tengo una configuración de manejador de señal para captar las señales, que luego establece una bandera que necesito para terminar la aplicación. El problema que tengo es que todas las funciones de la consola que puedo encontrar bloquean, lo que significa que no puedo detectar que necesito salir de mi bucle de procesamiento de la consola hasta que el usuario presiona una tecla (o ingresar, dependiendo de la función))

¿Hay alguna forma estándar de interacción con la consola sin bloque, o hay una forma elegante de estructurar el programa para que si acabo de terminar el hilo de señal, todo se maneje y se libere correctamente (por favor no entiendo mal esto, sé cómo se podría hacer esto bloqueando y soltando los recursos del hilo de señalización, pero esto podría ser complicado, así que preferiría evitarlo)

Espero que esa explicación tenga más sentido ...

Respuesta

6

En * nix, puede utilizar la función signal registrar un manejador de señales:


#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); 
    ... 
} 

Ahora, cada vez que alguien golpea Ctrl + C, el manejador de la señal será llamado.

0

En un sistema basado en * nix es posible que en realidad no necesite un manejador de señal para que esto funcione. Puede especificar que desea ignorar la llamada 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 
    } 
    } 
} 

La forma más importante que esto funciona es reconocer que las funciones no bloqueantes hacen llegar interrumpido. Normalmente, se daría cuenta de que la función de bloqueo falló (por ejemplo, read()) y reintentó la función. Si fuera algún otro valor, tomaría la acción relacionada con el error correspondiente.

8

OK - esto funciona para mí en Windows & es portátil - tenga en cuenta el #ifdef SIGBREAK - esta no es una señal estándar.

#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

Nota: en Windows, haga clic en el botón de cierre elevará código sig 'SIGBREAK' (ctrl- descanso) – 56ka

0

A * solución nix mejor que es hilo de seguridad es usar pthread_sigmask() en lugar de la señal().
Por ejemplo, esta es la forma de Signore SIGINT, SIGTERM y SIGPIPE en el hilo actual y futuro dado lugar a discusiones:

sigset_t waitset; 
sigemptyset(&waitset); 
sigaddset(&waitset, SIGINT); 
sigaddset(&waitset, SIGTERM); 
sigaddset(&waitset, SIGPIPE); 
pthread_sigmask(SIG_BLOCK, &waitset, NULL); 
Cuestiones relacionadas