c++ - sigusr1 - Cómo manejar una señal ctrl-break en una interfaz de línea de comando
señales en programacion (5)
En * nix, puede usar la función de signal
para registrar un manejador de señal:
#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 presiona Ctrl + C, se llamará a su manejador de señal.
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.
Editar: Debo disculparme por mi explicación de antes, aparentemente no hice un 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 en que pueda hacer una interacción de consola sin bloque, o hay una forma elegante de estructurar el programa de modo que si acabo de terminar del hilo de señal, todo será manejado y liberado correctamente (por favor no lo haga) -Entiendo esto, sé cómo se podría hacer esto mediante el bloqueo y la liberación de 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 ...
En Windows: SetConsoleCtrlHandler
En un sistema basado en * nix, quizás no necesites un manejador de señales para que 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 importante en que esto funciona es reconocer que las funciones sin bloqueo se interrumpen. Normalmente, se daría cuenta de que la función de bloqueo falló (por ejemplo, leer ()) y volver a intentar la función. Si fuera algún otro valor, tomaría la acción relacionada con el error correspondiente.
OK - esto funciona para mí en Windows y es portátil - observe 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;
}
Una solución mejor * nix que es segura para hilos es usar pthread_sigmask () en lugar de signal ().
Por ejemplo, así es como sigues SIGINT, SIGTERM y SIGPIPE en el hilo actual y los futuros hilos generados:
sigset_t waitset;
sigemptyset(&waitset);
sigaddset(&waitset, SIGINT);
sigaddset(&waitset, SIGTERM);
sigaddset(&waitset, SIGPIPE);
pthread_sigmask(SIG_BLOCK, &waitset, NULL);