UNIX信号小结(2)

早期的UNIX信号机制是不可靠的,原因在于信号可能丢失。主要体现在:① signal函数中对信号处理的设置 ② 无法阻塞信号

讨论不可靠机制之前,先介绍一下signal函数和sigaction函数,signal函数接口为void ( *singal(int signo,void (*func)(int)))(int) 看起来非常复杂,大意就是signal函数有两个参数,一个是int型的signo(也就是某类信号)一个void型的函数指针(该函数有一个int参数)。signal函数返回一个void型的函数指针,该函数同样有一个int参数。由于上面的声明太过复杂,一般都会把上面的声明改为

sigaction的接口为int sigaction(int signo,const struct sigaction*act,struct sigaction*oact)

与sigaction函数相关联的一个结构是sigaction结构。该结构有4个成员:① void  (*sa_handler)(int)  ② sigset_t sa_mask  ③ int sa_flags  ④ void (*sa_sigaction)(int,siginfo_t*,void*)

其中sa_sigaction与sa_flags暂时不讨论

sa_handler就是信号处理函数,而sa_mask在信号处理函数调用时会自动加入到信号掩码中(这样就能在处理某个信号期间阻塞其他信号,同类信号会自动加入,无需设置),退出时恢复为原值。

如果act不为NULL,则sigaction把signo的设置改为act的内容,如果oact不为NULL,则sigaction把原先signo的设置放到oact中。

早期的signal函数实现的是不可靠的信号机制。sigaction函数的出现替代了了早期的signal函数,现在很多系统使用sigaction实现signal

APUE里给出了用sigaction实现的signal函数

早期的不可靠信号机制的一个方面体现在,对于一个信号,即使设置了捕获函数,当信号被捕获后,其信号处理会自动恢复为默认值

因此往往出现这样的程序

但是这样的程序存在一个问题,在sigint开始到信号处理函数设置signal前,中间有一段时间窗口,如果这期间又发生了SIGINT信号,则会导致进程停止。

可能有些人会感到疑惑,在sigint中不是会导致SIGINT的阻塞吗?为什么一个新的SIGINT会导致进程停止?那是因为在早期的信号机制中,信号是无法阻塞的,而这同样会导致一些问题(例如上面那段)

看下面一段代码

在程序检测sig_int_flag以及调用pause之间有一个时间窗口,如果信号发生在这段时间,并且不再发生,则程序将永远阻塞。

我们需要某种机制,使得我们可以先阻塞某种信号,然后原子的解除信号阻塞并调用pause函数。UNIX系统因此提供了sigsuspend函数。

网上有这么一种说法,认为对于信号的排队问题也是导致不可靠信号的原因。个人认为这并不正确

考虑这样一个问题,如果程序进入了一个信号处理函数,在这期间发生了一到多个同样的信号,会怎么样??

使用signal函数或者sigaction函数设置信号处理函数后,在信号处理函数期间,该信号会自动加入到信号掩码中,一退出信号处理函数,信号掩码则复位为原先的值。因此,当在信号处理函数中,同类信号的发生会被屏蔽而保持未决状态,如果发送了多个此类信号的话,当信号不再被阻塞时,一般只发送信号一次(也就是所谓的丢失)。然而早期信号是无法阻塞的,既然是无法阻塞的,那么信号也就不可能排队,因此上面的说法并不成立。

有意思的是,UNIX对前32种信号不支持排队,而后32种信号(也被称为实时信号)则支持排队。

最后,考虑一个问题,使用signal函数和sigaction函数哪个更好??个人认为sigaction对比起signal函数有三个优点,第一个是有些系统为了保持向后兼容,支持旧的不可靠信号语义函数signal。第二个是signal函数无法做到在不改变信号当前设置的前提下,获取信号的设置,而sigaction则可以 第三 sigaction提供了一些额外的设置,能做到一些signal无法做到的事情,这些将在后面说到

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值