Linux----信号屏蔽与解除并递达

来源:互联网 发布:js上拉加载更多 编辑:程序博客网 时间:2024/05/29 12:15

先介绍有关信号的三个概念:

  • 信号未决(pending):信号从产生到递达之间的状态。
  • 信号递达(delivery):实际执行信号的处理动作。
  • 信号阻塞(block):进程可以选择阻塞某个信号。被阻塞的信号将保持在未决状态,知道解除阻塞,才执行递达的动作。
    注意:信号阻塞和忽略信号的区别:
    只要信号被阻塞就不会被递达。而忽略信号时在递达之后的一种处理动作。
    信号在内核中的表示示意图如下:
    这里写图片描述
    block:阻塞集信号。用位图表示,只需4字节。位图的下标表示信号的编号,内容为1,表示该信号阻塞,为0,表示该信号非阻塞。
    pending:未决信号集。用位图表示,只需4字节。位图的下标表示信号的编号,内容为1,表示收到该信号,为0,表示未收到该信号。
    handler:递达。设置对应信号的处理方式,SIG_DFL:表示默认。SIG_IGN:表示忽略。还可选择相应的处理函数指针。
    例如说图中的2号信号。收到了2号信号,但是2号信被阻塞,不能递达。该信号递达为忽略。
    未决和阻塞标志可以⽤用相同的数据类型sigset_t来存储,sigset_t称为信号集。
    阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask), 这里的“屏蔽”应该理解为阻塞⽽而不是忽略。
    下面介绍信号集的操作函数:
    int sigemptyset(sigset_t *set);
//将信号集清零
    int sigfillset(sigset_t *set);
//将信号集置位
    int sigaddset(sigset_t *set, int signo);//
添加某种有效信号
    int sigdelset(sigset_t *set, int signo);
//删除某种有效信号
    int sigismember(const sigset_t *set, int signo); //判断某种信号是否在该信号集里
    int sigprocmask(int how, const sigset_t *set, sigset_t *oset); //读取或更改信号的屏蔽字(阻塞信号集)
    如果oset是⾮非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是⾮非空指 针,则 更改进程的信号屏蔽字,参数how指⽰示如何更改。如果oset和set都是⾮非空指针,则先 将原来的信号 屏蔽字备份到oset⾥里,然后根据set和how参数更改信号屏蔽字。假设当前的 信号屏蔽字为mask,下表说明了how参数的可选值。
    how可选值如下:
    SIG_BLOCK:mask=mask|set
    SIG_UNBLOCK:mask=mask&~set
    SIG_SETMASK:mask=set
    如果调⽤用sigprocmask解除了对当前若⼲干个未决信号的阻塞,则在sigprocmask返回前,⾄至 少将其中 一个信号递达
    int sigpending(sigset_t *set);//读取当前进程的未决信号集,通过set参数传出。
    以上几个函数头文件为:signal.h
    以下举几个例子说明信号的屏蔽,解除后会递达的:
    例:测试几个函数,屏蔽2号信号后,当捕捉到2号信号后,观察未决信号集的内容。
    1 #include<stdio.h>
    2 #include<signal.h>
    3 void showpending(sigset_t* pending)//打印pending信号集
    4 {
    5 int i=1;
    6 for(;i<=31;i++)
    7 {
    8 if(sigismember(pending,i))//如果i信号在pending信号集中
    9 printf("1");//打印1
    10 else//如果i信号在pending信号集中
    11 printf("0");//打印0
    12
    13 }
    14 printf("\n");//使得上面的数据从缓冲区打印到显示器上
    15
    16 }
    17
    18 int main()
    19 {
    20 sigset_t blockset,oldblockset,pending;//分别设置一个阻塞信号集,旧的阻塞信号集,未决信号集
    21 sigemptyset(&blockset);//将信号集清零
    22 sigemptyset(&oldblockset); //将信号集清零
    23sigaddset(&blockset,2);//给blockset信号集添加2号信号
    25 sigprocmask(SIG_SETMASK,&blockset,&oldblockset);//将旧的阻塞集保存到oldblockset中,将新的阻塞集blockset通过SIG_SETMASK方法设置到PCB的阻塞集中(即就是将2号信号屏蔽)
    26 while(1)
    27 {
    28 sigpending(&pending);//获取未决信号集
    29 showpending(&pending);//打印未决信号集
    30 sleep(1);//睡眠1s
    31 }
    32 return 0;
    33 }

    结果为:
    这里写图片描述
    结果分析:符合预期。不断的获取未决信号集pending,发送2号信号后,pending信号集中第二个bit位为1.其他为0.
    例:测试几个函数,捕捉信号,屏蔽2号信号后,count累加为5时,恢复之前的阻塞集。在count为5之前,当捕捉到2号信号后,观察未决信号集的内容;在count为5之后,当捕捉到2号信号后,观察未决信号集的内容
1 #include<stdio.h>  2 #include<signal.h>  3 void showpending(sigset_t* pending)//打印pending信号集  4 {  5  int i=1;  6  for(;i<=31;i++)  7  {  8   if(sigismember(pending,i))//如果i信号在pending信号集中  9       printf("1");//打印1 10   else//如果i信号在pending信号集中 11       printf("0");//打印0 12  13  } 14  printf("\n");//使得上面的数据从缓冲区打印到显示器上 15  16 } 17 void handler(int sig) 18 { 19 printf("get a sig:%d\n",sig); 20 } 18 int main() 19 { 20 sigset_t blockset,oldblockset,pending;//分别设置一个阻塞信号集,旧的阻塞信号集,未决信号集 21 sigemptyset(&blockset);//将信号集清零 22 sigemptyset(&oldblockset); //将信号集清零 23sigaddset(&blockset,2);//给blockset信号集添加2号信号signal(2,handler); 25 sigprocmask(SIG_SETMASK,&blockset,&oldblockset);//将旧的阻塞集保存到oldblockset中,将新的阻塞集blockset通过SIG_SETMASK方法设置到PCB的阻塞集中(即就是将2号信号屏蔽)30 int count=0; 26 while(1) 27 { 28   sigpending(&pending);//获取未决信号集 29   showpending(&pending);//打印未决信号集 30   sleep(1);//睡眠1s       if((count++)==5) 37   { 38    printf("proc recover\n"); 39    sigprocmask(SIG_SETMASK,&oldblockset,NULL); 40   } 31 } 32 return 0; 33 }

这里写图片描述
例3,实现1-9s内2号信号被阻塞,10-19s内2号信号被释放,20S后2号信号被阻塞,观察pending信号集
这里写图片描述
这里写图片描述
结果为:
这里写图片描述

原创粉丝点击