信号处理程序实例在Linux编程接口

信号处理程序实例在Linux编程接口

问题描述:

从编程的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

通常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正在使用一个古怪的系统,但没有提到这样的情况。 –

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

+0

这不是我的代码;这是一本教科书的例子。作者得到你刚才提到的那一点:] – 8protons