2010-11-22 21 views
29

Tengo una clase con un destructor definido por el usuario. Si la clase fue instanciada inicialmente, y luego se emite SIGINT (usando CTRL + C en Unix) mientras el programa se está ejecutando, ¿se llamará al destructor? ¿Cuál es el comportamiento de SIGSTP (CTRL + Z en Unix)?¿Se llama a destructor si se emiten SIGINT o SIGSTP?

Respuesta

24

No, de forma predeterminada, la mayoría de las señales provocan una salida inmediata y anormal de su programa.

Sin embargo, puede cambiar fácilmente el comportamiento predeterminado para la mayoría de las señales.

Este código muestra cómo hacer una salida de señal de su programa normalmente, incluso llamando a todos los destructores de siempre:

#include <iostream> 
#include <signal.h> 
#include <unistd.h> 
#include <cstring> 
#include <atomic> 

std::atomic<bool> quit(false); // signal flag 

void got_signal(int) 
{ 
    quit.store(true); 
} 

class Foo 
{ 
public: 
    ~Foo() { std::cout << "destructor\n"; } 
}; 

int main(void) 
{ 
    struct sigaction sa; 
    memset(&sa, 0, sizeof(sa)); 
    sa.sa_handler = got_signal; 
    sigfillset(&sa.sa_mask); 
    sigaction(SIGINT,&sa,NULL); 

    Foo foo; // needs destruction before exit 
    while (true) 
    { 
     // do real work here... 
     sleep(1); 
     if(quit.load()) break; // exit normally after SIGINT 
    } 
    return 0; 
} 

Si ejecuta este programa y pulse control-C, debería ver la palabra "destructor" impreso. Tenga en cuenta que las funciones de su manejador de señal (got_signal) rara vez deben hacer otro trabajo, aparte de establecer una bandera y regresar silenciosamente, a menos que realmente sepa lo que está haciendo.

La mayoría de las señales son detectables como se muestra arriba, pero no SIGKILL, usted no tiene control sobre ello porque SIGKILL es un último método para matar un proceso fuera de control, y no SIGSTOP que permite a un usuario congelar un proceso frío. Tenga en cuenta que puede capturar SIGTSTP (control-Z) si lo desea, pero no necesita hacerlo si su único interés en las señales es el comportamiento del destructor, ya que después de un control-Z el proceso se activará, continuará ejecutándose y saldrá normalmente con todos los destructores en efecto.

+5

IIRC, el tipo correcto de 'quit' debe ser' volatile std :: sig_atomic_t'. Es UB usar 'bool' para ese propósito. – MSalters

+0

@MSalters: Correcto, debería haber incluido una llamada sigfillset() antes de sigaction(), que probablemente sería incluso mejor que sig_atomic_t. Usar un bool es más familiar y perfectamente seguro cuando se bloquean las señales adicionales para que no interrumpan el manejador de señal. Edito mi código de ejemplo, gracias. –

+2

En realidad recibo un error con este código: 'uso de la función eliminada' para la línea' quit = false'. Tienes que hacer 'quit (false)' en lugar de 'quit = false'. También vale la pena señalar que este código no funciona en Windows; tienes que usar 'SetConsoleCtrlHandler()'. – Timmmm

8

Si no maneja estas señales usted mismo, entonces, no, los destructores no son llamados. Sin embargo, el sistema operativo recuperará los recursos que su programa usó cuando finaliza.

Si desea manejar las señales usted mismo, entonces considere verificar la función de biblioteca estándar sigaction.

+3

Reclamando recursos propiedad del SO. Dentro de una aplicación hay otros recursos y generalmente se envuelven de tal forma que se requiere cerrarlos correctamente (de lo contrario, se obtienen recursos corruptos (como un archivo que no termina adecuadamente)). –

6

Intentémoslo:

#include <stdio.h> 
#include <unistd.h> 

class Foo { 
public: 
    Foo() {}; 
    ~Foo() { printf("Yay!\n"); } 
} bar; 

int main(int argc, char **argv) { 
    sleep(5); 
} 

Y luego:

$ g++ -o test ./test.cc 
$ ./test 
^C 
$ ./test 
Yay! 

Así que no tengo miedo, vas a tener que cogerlo.

Como para SIGSTOP, no se puede capturar, y detiene el proceso hasta que se envía SIGCONT.

Cuestiones relacionadas