【C】——sigprocmask 阻塞进程信号

1、有时候不希望在接到信号时就立即停止当前执行,去处理信号,同时也不希望忽略该信号,而是延时一段时间去调用信号处理函数。这种情况是通过阻塞信号实现的。

 

2、信号阻塞和忽略信号的区别。

阻塞的概念和忽略信号是不同的。操作系统在信号被进程解除阻塞之前不会讲信号传递出去,被阻塞的信号也不会影响进程的行为,信号只是暂时被阻止传递。当进程忽略一个信号时,信号会被传递出去但进程会将信号丢弃。

 

3、信号阻塞系统调用,它们的都起到阻塞的作用,它们不是协作使用的。

 

  1. #include <signal.h>  
  2.   
  3. int sigprocmask(ubt how,const sigset_t*set,sigset_t *oldset);  
  4.   
  5. 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     &nbsp;checkset();
13 
14      sigprocmask(SIG_SETMASK,&blockset,NULL);
15      checkset();
16 
17    &nbsp; 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    &nbsp;sigaddset(&blockset,SIGINT);//将SIGINT添加到信号量集中
16 
17    sigprocmask(SIG_SETMASK,&blockset,&oldblockset); //将blockset中的SIGINT,SIGTSTP阻塞掉,并保存当前信号屏蔽字
18 
19      /*执行以下程序时,不会被信号打搅*/
20     checkset();
21    &nbsp;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 &nbsp;    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       }

结果第一次发送的信号也会有响应,截图如下:

看来在阻塞信号的时候接收到了信号,当恢复信号屏蔽字的时候信号也会得到处理!

posted @ 2013-10-19 11:08  net小伙  阅读(1444)  评论(0编辑  收藏  举报