Linux编程接口中的信号处理程序示例

时间:2015-07-21 06:45:57

标签: c++ c linux operating-system signals

以下来自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

2 个答案:

答案 0 :(得分:5)

通常signal需要重新安装信号处理程序。否则,它会自动转换为SIG_DFL(对应于信号的默认操作)。 SIGINT的默认操作是终止程序。

请注意,printf(3)不是异步安全函数之一。所以你可以写(2)来做同样的事情。请参阅Async-signal-safe functions.

的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语义。

答案 1 :(得分:0)

您不应在信号和异常处理程序中使用printf(),因为它们不可重入。 printf还会在将数据放入控制台之前缓冲内存中的数据,因此使用fflush()将有助于打印但不推荐。为测试目的在处理程序中使用counter(flag)并使用printf外部处理程序。不要使用signal()来注册处理程序,因为unix(BSD,Linux)的每种风格都不提供相同的实现。而是使用sigaction。

相关问题