2015-07-21 74 views
3

從編程的Linux編程接口下面的示例邁克爾·凱里斯克信號處理程序實例在Linux編程接口

static void sigHandler(int sig){ 
    printf("Ouch!\n"); 
} 

int main(int argc, char *argv[]) 
{ 
    int j; 

    if (signal(SIGINT, sigHandler) == SIG_ERR) 
    errExit("signal"); 

    for (j = 0; ; j++){ 
     printf("%d\n", j); 
     sleep(3); 
    } 
} 

應該打印「哎喲!」每當用戶鍵入Control-C(CTRL + C)在作者自己的例子中,他在鍵入它兩次之後最終用Control- \(CTRL + \)退出終端。

當我這樣做時,程序按照預期在上工作,只有第一次執行CTRL + C。如果我第二次輸入它,就像作者在他的例子中所做的那樣,我的程序退出終端 - 它不打印「哎呀!」它也不會繼續運行(循環)。

我使用完全相同的代碼,這裏給出的,書上的網站:

Ouch.c

+0

作爲說明:至少在標準C++中(在信號處理程序中調用printf)是未定義的行爲 – MikeMB

回答

5

通常signal需要重新安裝的信號處理程序。否則,它會拒絕SIG_DFL(對應於該信號的默認操作)。 SIGINT的默認操作是終止程序。

請注意printf(3)不是異步安全功能之一。所以你可以寫(2)來做同樣的事情。見的POSIX清單Async-signal-safe functions.

重新安裝它應該按預期方式工作:

static void sigHandler(int sig){ 
    signal(SIGINT, sigHandler); 
    write(STDOUT_FILENO, "Ouch!\n", 6); 
} 

這就是爲什麼你應該避免signal和使用sigaction代替的原因之一。上述行爲不是跨平臺通用的。所以也許你所運行的平臺不是作者測試他的代碼或者你正在使用不同的Linux內核。

您需要在接收信號時重新安裝信號處理程序的行爲是System V行爲。但BSD語義不需要重新安裝。直到最近,Linux才顯示出系統V的行爲,但它似乎在最近的內核中得到了修復,我在3.19內核中看不到這一點,但可以看到2.6.32內核(相當老)。

信號的文檔狀態:

The situation on Linux is as follows: 

    * The kernel's signal() system call provides System V semantics. 

    * By default, in glibc 2 and later, the signal() wrapper function 
    does not invoke the kernel system call. Instead, it calls 
    sigaction(2) using flags that supply BSD semantics. This default 
    behavior is provided as long as the _BSD_SOURCE feature test macro 
    is defined. By default, _BSD_SOURCE is defined; it is also 
    implicitly defined if one defines _GNU_SOURCE, and can of course be 
    explicitly defined. 

    * On glibc 2 and later, if the _BSD_SOURCE feature test macro is not 
    defined, then signal() provides System V semantics. (The default 
    implicit definition of _BSD_SOURCE is not provided if one invokes 
    gcc(1) in one of its standard modes (-std=xxx or -ansi) or defines 
    various other feature test macros such as _POSIX_SOURCE, 
    _XOPEN_SOURCE, or _SVID_SOURCE; see feature_test_macros(7).) 

所以,你可以解決通過定義_BSD_SOURCE得到BSD語義。所以你觀察到的行爲很可能是因爲你的系統上的signal遵循System V語義和最近的Linux(可能是Kerrisk測試它)遵循BSD語義。

+0

這在近20年前的Linux(在libc級別)上得到修復。據推測OP正在使用一個古怪的系統,但沒有提到這樣的情況。 –

0

您不應該在信號和異常處理程序中使用printf(),因爲它們不可重入。在將其放入控制檯之前,printf還會緩衝內存中的數據,所以使用fflush()將有助於打印,但不推薦。爲了測試目的,在處理程序中使用counter(標誌)並使用printf外部處理程序。不要使用signal()來註冊處理程序,因爲每種unix(BSD,Linux)都不提供相同的實現。而是使用sigaction。

+0

這不是我的代碼;這是一本教科書的例子。作者得到你剛纔提到的那一點:] – 8protons