1,未决
前面提到过,通过修改 信号屏蔽字可以屏蔽信号。当内核发送了一个对当前进程而言已经被屏蔽的信号,且进程不忽略该信号,那么该信号就是未决的。它并不会被捕获,但是信号也没有消失。等到进程不再屏蔽它时,它就会被捕获。
注意,屏蔽与忽略是不同的。
进程屏蔽信号,信号还在,只是没被接收;
进程对信号的动作为忽略,那是进程已经接收到信号了,只是不采取任何动作。
如何获取当前进程的pending进程呢?调用sigpending来实现
#include<signal.h>
int sigpending(sigset_t *set);
2,例子
我们可以通过先屏蔽一个信号,再向进程发送这个信号,最后再取消对信号的屏蔽,来观察pending的效果。
代码可以在上一节的代码基础上修订,我们将main函数修改如下:
int main(){
//1,注册信号
if(signal(SIGUSR1, sig_usr_new) == SIG_ERR)
{
printf("can't catch SIGUSR1 !\n");
exit(1);
}
//2, 屏蔽SIGUSR1
sigset_t sigset, oldmask, pendmask;
//2.1 初始化sigset
if (sigemptyset(&sigset) < 0)
{
printf("sigemptyset error !\n");
exit(1);
}
//2.2 添加要屏蔽的信号
if (sigaddset(&sigset, SIGUSR1) < 0)
{
printf("add SIGUSR1 error!\n");
exit(1);
}
//2.3 修改当前信号屏蔽字
// 以前的屏蔽字保存进oldmask,便于后面恢复
if (sigprocmask(SIG_BLOCK, &sigset, &oldmask) < 0)
{
printf("can't block SIGUSR1!\n");
exit(1);
}
//3,休眠
sleep(10); //在休眠期间通过kill发送SIGUSR1
//4, 获取当前的pending信号
if(sigpending(&pendmask) < 0)
{
printf("pend error!\n");
exit(1);
}
//5,判断USR1是不是在pendmask里
if (sigismember(&pendmask, SIGUSR1))
{
printf("pending SIGSUR1\n");
}
//6,恢复信号屏蔽字
printf("\nstart to unblock SIGUSR1!\n");
if (sigprocmask(SIG_SETMASK, &oldmask, NULL))
{
printf("can't unblock SIGUSR1!\n");
exit(1);
}
printf("unblock SIGUSR1\n");
//7,死循环,为了防止进程退出
while(1){
pause();
}
}
我们在休眠期间通过kill发送SIGUSR1信号,效果如下:
➜ code g++ -g -W -o study_Linux study_Linux.c
➜ code ./study_Linux &
[1] 136
➜ code kill -USR1 136
➜ code pending SIGSUR1
start to unblock SIGUSR1!
recived SIGUSR, signo = 10
unblock SIGUSR1
我们可以看到,发送USR1后,其对应的signal handler并没有被马上调用,因为该信号被屏蔽了,或者说被pending了。
等我们取消该信号的屏蔽之后,其马上被捕获,出发signal handler。所以被屏蔽的信号并没有消失,只是在等待被捕获。
请注意,在第二次调用sigprocmask时的返回顺序。
第二次调用sigprocmask是取消对信号的屏蔽,取消后SIGUSR1对应的信号处理程序就会被调用。该信号处理程序(sig_usr_new)先返回,打印“recived SIGUSR, signo = 10”,然后sigprocmask才返回,打印“unblock SIGUSR1”。