Linux中常见信号量只有31个,所以进程PCB中表示常见的信号量只用一个字节表示就够了,进程得到了一个信号就是对应的一个bit位由0改变为1。信号被系统发送给一个进程,就是改变PCB中表示信号量的字节中对应的一个bit位。进程收到某一信号,相当于向表示信号量的字节中写入了一个信号量。
关于信号抵达,当信号产生后会向指定进程发送,但被发送的信号不会第一时间被抵达,进程也就不会产生相应的处理动作,所以信号存在信号未决和信号抵达这两种状态;而信号未决处于信号产生和信号抵达之间,所以,在信号抵达之前会存在一种情况叫做信号阻塞,被阻塞的信号是永远都不会在解除阻塞前被抵达的。
Linux为了方便管理用三张表来存储这些信息。
block表 表示被阻塞的信号(1为阻塞)
pending表 表示未决(1为有信号未达)
handler表 表示信号处理方式(有三种:忽略,默认,自定义)
具体关系如下表:
由表可以看出:
信号1被屏蔽,虽然现在没有信号1的信号未决情况,但就算是有信号1 被发送,因为被屏蔽也不会被抵达;除非解除对信号1的屏蔽,信号1抵达后会被忽略。
信号2没有被屏蔽,现在信号2处于信号未决情况,故信号1 最终会被抵达执行默认动作。
信号3被屏蔽,现在信号3处于信号未决情况,因为信号3被屏蔽也就不会被抵达;除非解除对信号3的屏蔽,信号3抵达后会执行自定义动作。
阻塞和忽略的区别:
被阻塞的信号永远都不会被抵达,而忽略是信号被抵达的一种处理动作。
同时需要知道的是,信号抵达后只有再合适的时机到来,才会被处理,即从内核态到用户态时。
打印pending表并验证信号屏蔽与解除并抵达的情况。
需要用到以下的几个函数:
源代码如下:
pending.c
1 #include<stdio.h>
2 #include<signal.h>
3 #include<stdlib.h>
4
5 void handler1(int flag){
6 printf("catch a signal,is num:%d\n", flag);
7 }
8
9 void handler2(int flag){
10 printf("catch a signal,is num:%d\n", flag);
11 exit(1);
12 }
13
14 void showpending(sigset_t *p){
15 int i=1;
16 for(; i<31; i++){
17 if(sigismember(p,i)){
18 printf("1");
19 }
20 else{
21 printf("0");
22 }
23 }
24 printf("\n");
25 }
27 int main(){
28 sigset_t s,p;
29 sigemptyset(&s);
30 sigaddset(&s,SIGINT);
31 printf("i block a signal:2\n");//屏蔽2号信号SIGINT
32 sigprocmask(SIG_BLOCK,&s, NULL);
33
34 int i=0;
35 while(1){
36 signal(3,handler1);//3号信号捕捉不退出
37 signal(20,handler1);//20号信号捕捉不退出
38 signal(2,handler2);//2号信号捕捉并退出
39 sigpending(&p);
40 showpending(&p);
41 sleep(1);
42 i++;
43 if(i == 10){
44 printf("i will unblock a signal:2\n");
45 sigprocmask(SIG_UNBLOCK,&s, NULL);//i等于10时,解除对2号信号SIGINT的屏蔽
46 }
47 }
48 return 0;
49 }
Makefile
运行结果如下
想知道为何这样运行,可以去看一看源代码,不多解释了。
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删