在《UNIX环境高级编程》中,作者写道:从UNIX System V派生的实现支持signal函数,但该函数提供旧的不可靠的语义,4.4BSD也提供signal函数,但它是按照sigaction函数定义的,所以在4.4BSD之下使用它提供新的可靠信号语义,目前大多数系统遵循这种策略。
在该书10.4节,作者举了两个不可靠信号的例子。一是如下代码,目的是不要调用一次信号处理函数之后就回到默认动作,而是一直使用该信号处理函数处理信号。但是问题是,在信号发生之后到信号处理程序调用signal之间的时间窗内有可能再次发生信号,第二次发生的信号会执行默认动作而不是注册的信号处理函数。
int sig_int();
...
signal(SIG_INT_, sig_int);
...
sig_int()
{
<span style="white-space:pre"> </span>signal(SIG_INT, sig_int);
<span style="white-space:pre"> </span>...
}
二是进程无法关闭信号而只能忽略它,使用标志位来处理,代码格式如下。但是在测试标志位和调用pause()的时间窗中,发生信号的话就会造成pause()永久休眠,因此也是不可靠的。
int sig_int();
int sig_int_flag;
main()
{
signal(SIGINT, sig_int);
...
while(sig_int_flag == 0)
pause();
...
}
sig_int()
{
signal(SIGINT, sig_int);
sig_int_flag = 1;
}
而sigaction可以避免这个问题,因而是可靠的。一般都建议使用sigaction()来代替signal函数。而实际在linux中,signal()库函数就是用sigaction()实现的。当然,signal()系统调用并不是这样,存在缺陷。在Linux终端man 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 pro‐
vided 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).)
* The signal() function in Linux libc4 and libc5 provide System V
semantics. If one on a libc5 system includes <bsd/signal.h> instead
of <signal.h>, then signal() provides BSD semantics.