信号之信号集操作

1、信号在内核中的表示
  执行信号的处理动作称为信号递达。信号从产生到递达状态之间的状态成为未决(pending)。
进程可以选择阻塞某个信号。被阻塞的信号产生时将保持在未决状态。直到进程解除对此信号的阻塞,才可以执行递达动作。
  如下图,进程任务结构(PCB)中包含:信号屏蔽字64位,linux中用sigset_t类型表示(block 1,信号掩码); 

未决状态字(pending 1)...阻塞信号的话,到达就会处于未决。

  如图,SIGINT信号,发送给进程,进程信号屏蔽字屏蔽信号,那么其被阻塞,也处于未决状态。当将信号屏蔽改为0,信号就会递达,进而执行信号处理函数。

信号集操作函数,下面这5个函数只是会改变信号集中的信号屏蔽字,但是并不会改变进程的信号屏蔽字。

1、int sigemptyset(sigset_t *set);//清空

2、int sigfillset(sigset_t *set);//置1

3、int sigaddset(sigset_t *set,int signo);

4、int sigdelset(sigset_t *set,int signo);

5、int sigismember(const sigset_t *set,int signo);

 

sigprocmask函数可以获取或者改变进程中的信号屏蔽字。

  int sigprocmask(int how,const sigset_t *set,sigset_t *oset);

  功能:读取或者更改进程的信号屏蔽字。成功返回0,出错返回-1.

如果oset是非空指针,则读取进程的当前的信号屏蔽字,通过oset参数传出。如果set是非空指针,则将进程信号屏蔽字改为set.参数how指示如何更改。如果oset和set都是非空指针,则先将原来的信号屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前信号屏蔽字为mask,

那么how参数含义:

SIG_BLOCK:set包含了我们希望添加到当前信号屏蔽字的信号,相当于mask=mask|set;

SIG_UNBLOCK:set包含了我们希望从当前信号屏蔽字中解除阻塞的信号,相当于mask=mask&~set;

SIG_SETMASK:设置当前信号屏蔽字为set所指向的值,相当于mask=set.

 

下面的例子说明信号从产生到递达的过程:

 1 #include<unistd.h>
 2 #include<sys/types.h>
 3 #include<sys/stat.h>
 4 #include<fcntl.h>
 5 #include<stdlib.h>
 6 #include<stdio.h>
 7 #include<errno.h>
 8 #include<string.h>
 9 
10 #include<signal.h>
11 #define ERR_EXIT(m)\
12     do\
13     {\
14         perror(m);\
15         exit(EXIT_FAILURE);\
16     }while(0)  //宏要求一条语句
17 void handler(int sig);
18 void printsigset(sigset_t *set)
19 {
20     int i;//NSIG表示信号最大值,64
21     for(i=1;i<NSIG;i++){
22         if(sigismember(set,i))
23             putchar('1');
24         else putchar('0');
25     }
26     printf("\n");
27 }
28 int main(int argc,char*argv[])
29 {
30     sigset_t pset;
31     sigset_t bset;
32     sigemptyset(&bset);//sigset_t 用之前必须置0或置1
33     if(signal(SIGINT,handler)==SIG_ERR)
34         ERR_EXIT("signal error");
35 //    if(signal(SIGQUIT,handler)==SIG_ERR)
36 //        ERR_EXIT("signal error");//再安装一个信号,按下ctrl+\解除SIGINT阻塞,信号递达(信号处理函数)
37     sigaddset(&bset,SIGINT);//SIGINT加入信号集。
38     sigprocmask(SIG_BLOCK,&bset,NULL);//对bset操作,改变信号屏蔽字,阻塞SIGIN信号。按下ctrl+c也会被阻塞。这个是不可靠信号,只会阻塞一个信号,不会排队。
39     for(;;)
40     {
41         sigpending(&pset);//获取未决信号,没有阻塞则没有未决
       /*
        sigpending函数返回信号集,其中的各个信号对于调用进程是阻塞的而不能递送,因而也一定是当前未决的。该信号集通过set参数返回。(这些信号是已经产生的信号,
但因为信号屏蔽字中对其设置了屏蔽位,从而被阻塞,不能递送给进程的那些信号。注意sigpending返回的信号集与信号屏蔽字的区别。从集合角度来讲,此信号集是当前信号屏蔽字的子集。)
        */
42 sleep(1); 43 printsigset(&pset); 44 sleep(1); 45 } 46 sleep(1); 47 return 0; 48 } 49 50 void handler(int sig)//sig是signum 51 { 52 if(sig==SIGINT) 53 printf("receive a sig %d\n",sig); 54 /* else if(sig==SIGQUIT) 55 { 56 sigset_t uset; 57 sigemptyset(&uset); 58 sigaddset(&uset,SIGINT); 59 sigprocmask(SIG_UNBLOCK,&uset,NULL);//解除uset中信号的阻塞 60 } 61 */ 62 }

 

posted on 2018-01-27 19:35  wsw_seu  阅读(338)  评论(0编辑  收藏  举报

导航