Dominar el manejo de señales en C++: Gestión segura de interrupciones y terminación limpia del programa
Las señales son interrupciones enviadas a un proceso por el sistema operativo que pueden terminar un programa prematuramente. Puedes generar interrupciones presionando Ctrl+C en sistemas UNIX, Linux, macOS o Windows.
Existen señales que no pueden ser capturadas por el programa, pero a continuación se muestra una lista de señales que sí puedes capturar en tu código y tomar las acciones apropiadas según la señal recibida. Estas señales están definidas en el archivo de cabecera de C++ <csignal>.
| Nº | Señal y descripción |
|---|---|
| 1 | SIGABRT Terminación anormal del programa, como una llamada a abort. |
| 2 | SIGFPE Operación aritmética errónea, como división por cero o desbordamiento. |
| 3 | SIGILL Detección de una instrucción ilegal. |
| 4 | SIGINT Recepción de una señal de atención interactiva (Ctrl+C). |
| 5 | SIGSEGV Acceso inválido a almacenamiento (violación de segmento). |
| 6 | SIGTERM Solicitud de terminación enviada al programa. |
La función signal()
La biblioteca de manejo de señales de C++ proporciona la función signal para atrapar eventos inesperados. La sintaxis de la función signal() es:
void (*signal (int sig, void (*func)(int)))(int);
Simplificando, esta función recibe dos argumentos: el primero es un entero que representa el número de señal, y el segundo es un puntero a la función manejadora de señales.
Veamos un programa simple en C++ donde capturamos la señal SIGINT usando la función signal(). Cualquier señal que quieras capturar en tu programa debe registrarse usando la función signal y asociarse con un manejador de señales. Examina el siguiente ejemplo:
#include <iostream>
#include <csignal>
#include <unistd.h>
using namespace std;
void signalHandler(int signum) {
cout << "Señal de interrupción (" << signum << ") recibida.\n";
// Limpieza y cierre de recursos aquí
// Terminar programa
exit(signum);
}
int main() {
// Registrar señal SIGINT y su manejador
signal(SIGINT, signalHandler);
while(true) {
cout << "Durmiendo...." << endl;
sleep(1);
}
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:
Durmiendo....
Durmiendo....
Durmiendo....
Ahora, presiona Ctrl+C para interrumpir el programa y verás que tu programa captura la señal y sale imprimiendo algo como sigue:
Durmiendo....
Durmiendo....
Durmiendo....
Señal de interrupción (2) recibida.
La función raise()
Puedes generar señales mediante la función raise(), que toma un número de señal entero como argumento y tiene la siguiente sintaxis:
int raise(int sig);
Aquí, sig es el número de señal a enviar, cualquiera de las señales: SIGINT, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGTERM, SIGHUP. A continuación, un ejemplo donde generamos una señal internamente usando la función raise():
#include <iostream>
#include <csignal>
#include <unistd.h>
using namespace std;
void signalHandler(int signum) {
cout << "Señal de interrupción (" << signum << ") recibida.\n";
// Limpieza y cierre de recursos aquí
// Terminar programa
exit(signum);
}
int main() {
int i = 0;
// Registrar señal SIGINT y su manejador
signal(SIGINT, signalHandler);
while(++i) {
cout << "Durmiendo...." << endl;
if(i == 3) {
raise(SIGINT);
}
sleep(1);
}
return 0;
}
Cuando el código anterior se compila y ejecuta, produce el siguiente resultado y sale automáticamente:
Durmiendo....
Durmiendo....
Durmiendo....
Señal de interrupción (2) recibida.
Lenguaje C
- Entendiendo los Tipos de Datos en C++: Fundamentos, Modificadores y Mejores Prácticas
- Dominando los Operadores en C++: Guía Completa con Ejemplos Prácticos
- Comentarios en C++: Mejores Prácticas para Código Legible y Mantenible
- Dominando las plantillas de clase en C++: guía práctica
- Manejo de archivos en C: Dominando E/S con fopen, fprintf, fread y fseek
- Manejo de excepciones en C++: Guía práctica con try, catch, throw
- Manejo de Errores en C: Mejores Prácticas y Técnicas
- Lenguaje de Programación C++: Visión General y Características Clave
- Constantes y Literales en C++: Tipos, Sintaxis y Mejores Prácticas
- Guía Completa de Operadores en C++: Tipos, Uso y Mejores Prácticas
- Dominando los Tipos Numéricos en C++: Guía Práctica