簡體   English   中英

Linux編程接口中的信號處理程序示例

[英]Signal Handler Example in The Linux Programming Interface

以下來自Michael Kerrisk編程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

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

請注意, printf(3)不是異步安全函數之一。 所以你可以寫(2)來做同樣的事情。 請參見異步信號安全功能的POSIX列表

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

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

這是您應該避免signal並使用sigaction的原因之一。 上述行為並非跨平台通用。 或許,你運行的平​​台不是作者測試他的代碼或你正在使用不同的Linux內核。

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

Signal的文檔說明:

  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語義。

你不應該在信號和異常處理程序中使用printf(),因為它們不是可重入的。 printf還會在將數據放入控制台之前緩沖內存中的數據,因此使用fflush()將有助於打印但不推薦。 為測試目的在處理程序中使用counter(flag)並使用printf外部處理程序。 不要使用signal()來注冊處理程序,因為unix(BSD,Linux)的每種風格都不提供相同的實現。 而是使用sigaction。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM