2010-11-22 6 views

Antwort

24

Nein, standardmäßig verursachen die meisten Signale einen sofortigen, anormalen Ausgang Ihres Programms.

Sie können jedoch das Standardverhalten für die meisten Signale leicht ändern.

Dieser Code zeigt, wie ein Signal Ausgang Ihr Programm normal zu machen, einschließlich der Aufforderung alle üblichen Destruktoren:

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

Wenn Sie das Programm und drücken Steuer-C ausführen, sollten Sie das Wort „destructor“ sehen gedruckt. Seien Sie sich bewusst, dass Ihre Signal-Handler-Funktionen (got_signal) selten funktionieren sollten, außer dass Sie eine Markierung setzen und ruhig zurückkehren, es sei denn, Sie wissen wirklich, was Sie tun.

Die meisten Signale sind abfangbare, wie oben gezeigt, aber nicht SIGKILL, Sie haben keine Kontrolle über sie, weil SIGKILL ein letzter verzweifelter Methode ist es, einen außer Kontrolle geratenen Prozess für das Töten und SIGSTOP nicht, welche einem Benutzer ermöglicht, einen Prozess kalt einzufrieren. Beachten Sie, dass Sie bei Bedarf SIGTSTP (control-Z) abfangen können. Dies ist jedoch nicht erforderlich, wenn Ihr einziges Interesse an Signalen das Destruktorverhalten ist, da der Prozess schließlich nach einem control-Z aktiviert wird, weiterläuft und wird normal mit allen aktiven Destruktoren beendet.

+5

IIRC, der korrekte Typ von 'quit' sollte' volatile std :: sig_atomic_t' sein. Es ist UB, 'bool' zu diesem Zweck zu verwenden. – MSalters

+0

@MSalters: Richtig, ich hätte einen sigfillset() Aufruf vor sigaction() eingefügt, was wahrscheinlich sogar besser als sig_atomic_t wäre. Die Verwendung eines Bool ist vertrauter und vollkommen sicher, wenn zusätzliche Signale daran gehindert werden, den Signal-Handler zu unterbrechen. Bearbeitet meinen Beispielcode, danke. –

+2

Ich bekomme tatsächlich einen Fehler mit diesem Code: 'Verwendung der gelöschten Funktion' für die' quit = false' Zeile. Du musst 'quit (false)' anstelle von 'quit = false' machen. Beachten Sie auch, dass dieser Code unter Windows nicht funktioniert. Sie müssen 'SetConsoleCtrlHandler()' verwenden. – Timmmm

8

Wenn Sie diese Signale nicht selbst behandeln, dann werden die Destruktoren nicht aufgerufen. Das Betriebssystem wird jedoch alle Ressourcen zurückfordern, die von Ihrem Programm beim Beenden verwendet wurden.

Wenn Sie Signale selbst verarbeiten möchten, sollten Sie die Standardbibliotheksfunktion sigaction ausprobieren.

+3

Zurückfordern von Ressourcen, die dem Betriebssystem gehören. Innerhalb einer Anwendung gibt es noch andere Ressourcen, die normalerweise so eingepackt sind, dass sie korrekt geschlossen werden müssen (andernfalls erhalten Sie beschädigte Ressourcen (wie eine Datei, die nicht ordnungsgemäß beendet wird)). –

6

Lassen Sie uns es versuchen:

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

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

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

Und dann:

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

So habe ich Angst nicht, Sie werden es fangen.

Wie für SIGSTOP, kann es nicht gefangen werden, und pausiert den Prozess, bis eine SIGCONT gesendet wird.