信号之sigsuspend函数


更改进程的信号屏蔽字可以阻塞所选择的信号,或解除对它们的阻塞。使用这种技术可以保护不希望由信号中断的代码临界区。如果希望对一个信号解除阻塞,然后pause等待以前被阻塞的信号发生,则又将如何呢?假定信号时SIGINT,实现这一点的一种不正确的方法是:

&&
(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 
(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 

如果在信号阻塞时将其发送给进程,那么该信号的传递就被推迟直到对它解除了阻塞。对应用程序而言,该信号好像发生在解除对SIGINT的阻塞和pause之间。如果发生了这种情况,或者如果在解除阻塞时刻和pause之间确实发生了信号,那么就产生了问题。因为我们可能不会再见到该信号,所以从这种意义上而言,在此时间窗口(解除阻塞和pause之间)中发生的信号丢失了,这样就使pause永远阻塞。

为了纠正此问题,需要在一个原子操作中先恢复信号屏蔽字,然后使进程休眠。这种功能是由sigsuspend函数提供的。

#include <signal.h>

 sigsuspend(  sigset_t *-,并将errno设置为EINTR

sig_int((signal(SIGINT, sig_int) ==&&&& (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < (sigsuspend(&waitmask) != - (sigprocmask(SIG_SETMASK, &oldmask, NULL) <

运行该程序的结果如下:

sig_atomic_t quitflag; signo) signal(SIGINT, sig_int); signal(SIGQUIT, sig_int); (signo == (signo === ; (signal(SIGINT, sig_int) ==(signal(SIGQUIT, sig_int) ==&&& (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < (quitflag == &= (sigprocmask(SIG_SETMASK, &oldmask, NULL) <

注意,程序清单10-16中标记为红色字体的两行在《UNIX环境高级编程》中本来是没有的,但是不加这两行,在我的运行环境下(Red Hat Linux 2.6.18)得不到跟书中一样的运行结果:

书中的运行结果(可以反复键入中断字符):

sig_atomic_t sigflag; signo) = (signal(SIGUSR1, sig_usr) == (signal(SIGUSR2, sig_usr) ==&&&& (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < (sigflag == &zeromask); = (sigprocmask(SIG_SETMASK, &oldmask, NULL) < (sigflag == &zeromask); = (sigprocmask(SIG_SETMASK, &oldmask, NULL) <

其中使用了两个用户定义的信号:SIGUSR1由父进程发送给子进程,SIGUSR2由子进程发送给父进程。

如果在等待信号发生时希望去休眠,则使用sigsuspend函数是非常合适的,但是如果在等待信号期间希望调用其他系统函数,那么将会怎样呢?不幸的是,在单线程环境下对此问题没有妥善的解决方法。如果可以使用多线程,则可专门安排一个线程处理信号。

如果不使用线程,那么我们能尽力做到最好的是,当信号发生时,在信号捕捉程序中对一个全局变量置1.

 

本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/

相关内容