2010-11-22 79 views

回答

24

不,默認情況下,大多數信號會導致程序立即異常退出。

但是,您可以輕鬆更改大多數信號的默認行爲。

這段代碼演示瞭如何使一個信號,退出你的程序正常,包括調用所有常見的析構函數:

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

如果你運行這個程序,並按下控制-C,你應該看到「析構函數」打印。請注意,除非您真的知道您在做什麼,否則您的信號處理函數(got_signal)應該很少做任何工作,除非設置標誌並安靜地返回。

大多數信號如上所示是可捕獲的,但不是SIGKILL,您無法控制它,因爲SIGKILL是殺死失控進程的最後一種方法,而不是SIGSTOP,它允許用戶凍結進程冷卻。請注意,如果需要,您可以捕獲SIGTSTP(control-Z),但如果您對信號的唯一興趣是析構函數行爲,則不需要,因爲最終在控制-Z過程將被喚醒後,將繼續運行,並且將正常退出所有的析構函數。

+5

IIRC,`quit`的正確類型應該是`volatile std :: sig_atomic_t`。爲此目的使用`bool`是UB。 – MSalters 2010-11-23 09:29:36

8

如果你自己不處理這些信號,那麼,不,不會調用析構函數。但是,操作系統將在程序終止時回收您的程序使用的任何資源。

如果您希望自己處理信號,請考慮檢查sigaction標準庫函數。

+3

回收操作系統擁有的資源。在一個應用程序中還有其他的資源,它們通常以這樣一種方式包裝,即正確關閉它們(否則你會得到損壞的資源(如未正確終止的文件))。 – 2010-11-22 23:24:24

6

讓我們試一下:

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

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

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

然後:

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

所以恐怕不行,你必須抓住它。

至於SIGSTOP,它不能被捕獲,並暫停處理,直到發送一個SIGCONT

相關問題