【C】——sigprocmask 阻塞进程信号
1、有时候不希望在接到信号时就立即停止当前执行,去处理信号,同时也不希望忽略该信号,而是延时一段时间去调用信号处理函数。这种情况是通过阻塞信号实现的。
2、信号阻塞和忽略信号的区别。
阻塞的概念和忽略信号是不同的。操作系统在信号被进程解除阻塞之前不会讲信号传递出去,被阻塞的信号也不会影响进程的行为,信号只是暂时被阻止传递。当进程忽略一个信号时,信号会被传递出去但进程会将信号丢弃。
3、信号阻塞系统调用,它们的都起到阻塞的作用,它们不是协作使用的。
- #include <signal.h>
- int sigprocmask(ubt how,const sigset_t*set,sigset_t *oldset);
- int sigsuspend(const sigset_t*sigmask);
sigprocmask设定对信号屏蔽集内的信号的处理方式(阻塞或不阻塞)。
参数:
how:用于指定信号修改的方式,可能选择有三种
SIG_BLOCK//将set所指向的信号集中包含的信号加到当前的信号掩码中。即信号掩码和set信号集进行或操作。
SIG_UNBLOCK//将set所指向的信号集中包含的信号从当前的信号掩码中删除。即信号掩码和set进行与操作。
SIG_SETMASK //将set的值设定为新的进程信号掩码。即set对信号掩码进行了赋值操作。
set:为指向信号集的指针,在此专指新设的信号集,如果仅想读取现在的屏蔽值,可将其置为NULL。
oldset:也是指向信号集的指针,在此存放原来的信号集。可用来检测信号掩码中存在什么信号。
返回说明:
成功执行时,返回0。失败返回-1,errno被设为EINVAL。
sigprocmask示例(演示添加信号掩码):
1 #include <stdio.h> 2 #include <signal.h> 3 void checkset(); 4 5 void main() 6 { 7 sigset_tblockset; 8 sigemptyset(&blockset); 9 sigaddset(&blockset,SIGINT); 10 sigaddset(&blockset,SIGTSTP); 11 12 checkset(); 13 14 sigprocmask(SIG_SETMASK,&blockset,NULL); 15 checkset(); 16 17 sigaddset(&blockset,SIGTERM); 18 sigprocmask(SIG_BLOCK,&blockset,NULL); 19 checkset(); 20 21 sigdelset(&blockset,SIGTERM); 22 sigprocmask(SIG_UNBLOCK,&blockset,NULL); 23 checkset(); 24 } 25 26 void checkset() 27 { 28 29 sigset_tset set; 30 printf("checksetstart:\n"); 31 32 if(sigprocmask(0,NULL,&set)<0) 33 { 34 printf("checksetsigprocmask error!!\n"); 35 exit(0); 36 } 37 38 if(sigismember(&set,SIGINT)) 39 printf("sigint\n"); 40 if(sigismember(&set,SIGTSTP)) 41 printf("sigtstp\n"); 42 43 if(sigismember(&set,SIGTERM)) 44 printf("sigterm\n"); 45 printf("checksetend\n"); 46 }
sigprocmask示例(演示添某部分代码不被信号打搅):
1 #include <stdio.h> 2 #include <signal.h> 3 void checkset(); 4 5 void func(); 6 void main() 7 { 8 sigset_tblockset,oldblockset,pendmask; 9 printf("pid:%ld\n",(long)getpid()); 10 11 signal(SIGINT,func); //信号量捕捉函数,捕捉到SIGINT,跳转到函数指针func处执行 12 13 sigemptyset(&blockset); //初始化信号量集 14 sigaddset(&blockset,SIGTSTP); //将SIGTSTP添加到信号量集中 15 sigaddset(&blockset,SIGINT);//将SIGINT添加到信号量集中 16 17 sigprocmask(SIG_SETMASK,&blockset,&oldblockset); //将blockset中的SIGINT,SIGTSTP阻塞掉,并保存当前信号屏蔽字 18 19 /*执行以下程序时,不会被信号打搅*/ 20 checkset(); 21 sleep(5); 22 sigpending(&pendmask); //检查信号是悬而未决的 23 if(sigismember(&pendmask,SIGINT)) //SIGINT是悬而未决的。所谓悬而未决,是指SIGQUIT被阻塞还没有被处理 24 printf("SIGINTpending\n"); 25 26 /*免打搅结束*/ 27 28 sigprocmask(SIG_SETMASK,&oldblockset,NULL); //恢复被屏蔽的信号SIGINT SIGTSTP 29 printf("SIGINTunblocked\n"); 30 sleep(6); 31 } 32 33 void checkset() 34 { 35 sigset_tset; 36 printf("checksetstart:\n"); 37 if(sigprocmask(0,NULL,&set)<0) 38 { 39 printf("checksetsigprocmask error!!\n"); 40 exit(0); 41 } 42 if(sigismember(&set,SIGINT)) 43 printf("sigint\n"); 44 45 if(sigismember(&set,SIGTSTP)) 46 printf("sigtstp\n"); 47 48 if(sigismember(&set,SIGTERM)) 49 printf("sigterm\n"); 50 51 printf("checksetend\n"); 52 53 } 54 void func() 55 { 56 printf("hellofunc\n"); 57 }
sigeprocmask函数通常和sigemptyset、sigfillset、sigaddset、sigdelset、 sigismember函数配合使用,主要有两种用途:
1.我们不希望某些不太重要的信号来影响我们的进程,我们就可以把这些信号添加到信号屏蔽集中。使它们不打扰进程的执行。
2.如果系统现在很忙,没有时间及时相应信号,进程可以先把信号阻塞掉,等系统有空闲时间在去相应,这也保证了信号的可靠性。
例二:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<signal.h> 4 5 sigset_t newmask,oldmask,pendmask; 6 7 void sig_usr(int signo) 8 { 9 printf("this is sig_usr!\n"); 10 11 } 12 13 int main(int argc, char *argv[]) 14 { 15 16 if(signal(SIGUSR1,sig_usr) == SIG_ERR){ 17 printf("signal error!\n"); 18 exit(1); 19 } 20 21 sigemptyset(&newmask); 22 sigaddset(&newmask,SIGUSR1); 23 if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0){ 24 printf("sig_block error!\n"); 25 exit(1); 26 } 27 28 printf("first raise(SIGUSR1)!\n"); 29 raise(SIGUSR1); 30 if(sigpending(&pendmask) < 0){ 31 printf("sigpending error!\n"); 32 exit(1); 33 } 34 35 if(sigismember(&pendmask, SIGUSR1)) 36 printf("sigusr1 pending!\n"); 37 38 if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0){ 39 printf("sig_setmask error!\n"); 40 exit(1); 41 } 42 43 printf("second raise(SIGUSR1)!\n"); 44 raise(SIGUSR1); 45 46 printf("main end!\n"); 47 exit(0); 48 }
结果如下:
如果注释掉下面的代码
1 if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0){ 2 printf("sig_setmask error!\n"); 3 exit(1); 4 }
结果如下:
发现第一次发送的信号也不会处理了。笔者也不知道为什么会发生这种情况,还是下次写代码的时候注意一下,阻塞完信号,处理的时候要及时恢复好了!
若只注释掉下面的代码:
1 if(sigpending(&pendmask) < 0){ 2 printf("sigpending error!\n"); 3 exit(1); 4 } 5 6 if(sigismember(&pendmask, SIGUSR1)) 7 printf("sigusr1 pending!\n");
而留下:
1 if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0){ 2 printf("sig_setmask error!\n"); 3 exit(1); 4 }
结果第一次发送的信号也会有响应,截图如下:
看来在阻塞信号的时候接收到了信号,当恢复信号屏蔽字的时候信号也会得到处理!