Linux入门:信号(二)——阻塞信号
实际执行信号的处理动作称为信号递达(Delivery)。
信号从产生到递达之间的状态,称为信号未决(Pending)。
进程可以选择阻塞(Block)某个信号。被阻塞的信号产生时将保持在未决状态,直到进程接触对此信号的阻塞,才执行递达的操作。(阻塞和忽略不同,只有信号阻塞就不会递达,而忽略是在信号递达之后可选的一种处理动作。而一个被阻塞的信号想要递达,需要先Pending再解除阻塞。)
每个信号都有两个标志位分别表示阻塞和未决,还有一个函数指针表示处理动作。信号产生时,内核在进程的PCB设置该信号的未决标志,直到信号递达才清除该标志。
如果进程在解除对某信号的阻塞之前这种信号产生了多次,将如何处理?POSIX.1允许系统递达信号一次或多次。在Linux中:常规信号在递达之前产生多次只计一次,实时信号在递达之前产生多次可以依次放在一个队列里。对于常规信号,每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集。
信号的阻塞就是让系统暂时保留信号待以后发送。由于另外有办法让系统忽略信号,所以一般情况下信号的阻塞只是暂时的,只是为了防止信号打断敏感的操作。当需要修改某些全局变量时,可以通过sigprocmask()函数阻塞处理函数中也使用该变量的信号。在某些信号处理函数中,为了防止同类信号的到来,可以使用sigaction()函数的sa_mask阻塞特定的信号。
阻塞信号的作用:使用函数sigprocmask()阻塞信号的传递,只是延迟信号的到达。信号会在解除阻塞后继续传递。这种情况往往需要在信号程序和其它程序共享全局变量时,如果全局变量的类型不是sig_atomic_t类型,当一部分程序恰好读、写到变量过程中,产生某个信号,而信号程序里会改变该变量,那么就会产生混乱。为了避免这种混乱,提供程序的可靠性,你必须在操作这类变量前阻塞信号,操作完成后恢复信号的传递。
#include <stdio.h>
#include <signal.h>
void handler(int sig)
{
printf("sig = %d\n", sig);
}
void show_pending(sigset_t *pending)
{
int i = 1;
for(i=1; i<=31; i++)
{
//判断指定信号是否在目标信号集中
if(sigismember(pending, i))
{
printf("1");
}
else
{
printf("0");
}
}
printf("\n");
}
int main()
{
//捕捉2号信号
signal(2, handler);
sigset_t block;
sigset_t oldblock;
sigset_t pending;
sigemptyset(&block);
sigemptyset(&oldblock);
//设置阻塞信号集,阻塞2号信号
sigaddset(&block, 2);
sigprocmask(SIG_SETMASK, &block, &oldblock);
int count = 0;
while(1)
{
//获取未决信号集
sigpending(&pending);
show_pending(&pending);
sleep(1);
count++;
if(count == 10)
{
//解除对当前未决信号的阻塞
sigprocmask(SIG_SETMASK, &oldblock, NULL);
}
}
return 0;
}
运行结果:上一篇: Linux进程间通信--信号
下一篇: 启用了不安全的HTTP方法