信号集,信号的阻塞
- 未决信号: 未完成的信号,即信号产生了但是没有被处理。比如pending中的二三号信号。
- 信号阻塞: 当信号到达以后,进程不对它做任何处理。比如blocking中搞得三四号信号。
- 每个进程的PCB当中都维护这样两个数组,blocking和pending, 这是种特殊的数组,简称为信号集,每一位只能取值0或1.
- handle代表对信号的处理, SIG_IGN: 忽略, SIG_DFL: 默认,user define: 自定义
- 上图中:
- 进程对一号信号不阻塞,但一号信号还没有发生(pending==0) 。 如果一号信号发生(pending==1), 待信号达时到进程将忽略它。
- 进程对二号信号不阻塞,二号信号已经产生,但没有处理。待二号信号到达,进程会默认处理
- 进程对三号信号阻塞,且三号信号已经发生但没处理,因为阻塞没有办法把信号抵达给进程。待三号信号阻塞解除,信号就可以抵达给进程,会使用用户自定义的函数进行处理。
1. 信号集
信号集类型 sigset_t 是结构体类型。一种类型,能够保存多个信号
typedef struct
{
unsigned long int __val[(1024 / (8 * sizeof (unsigned long int)))];
} __sigset_t;
typedef __sigset_t sigset_t;
跟信号集类型相关的操作如下:
sigemptyset
sigfillset
sigaddset
- set 需要已经初始化过的的具体的信号集
sigdelset
- set 需要已经初始化过的的具体的信号集
sigismember
- set 需要已经初始化过的的具体的信号集
#include <signal.h>
#include <stdio.h>
#define E_MSG(STRING, VAL) do{perror(STRING); return(VAL);}while(0)
int main(void){
// 定义信号集类型变量set, 它是一个结构体类型
sigset_t set;
// 初始化信号集set为空
sigemptyset(&set);
// 将2,3号信号添加到信号集set中
sigaddset(&set, 2);
sigaddset(&set, 3);
//测试3号信号是否为信号集中的一员
int is = sigismember(&set, 3);
if(is==-1)E_MSG("sigismember", -1);
if(is)
printf("signum 3 is member of set.\n");
else
printf("signum 3 is not member of set.\n");
// 将3号信号从信号中移除
sigdelset(&set, 3);
is = sigismember(&set, 3);
if(is==-1)E_MSG("sigismember", -1);
if(is)
printf("after del, signum 3 is member of set.\n");
else
printf("after del, signum 3 is not member of set.\n");
}
$ ./a.out
signum 3 is member of set.
after del, signum 3 is not member of set.
2. 信号的阻塞
sigprocmask
- 因为没有const,oldset 信号集里的内容有可能会被改变
- 信号掩码集就是阻塞信号集, 用来屏蔽掉信号集中为1 的信号
- ctrl c 是2号信号,ctrl \ 是3号信号, 可以被阻塞,但是9号信号今天的这例子中没有办法被阻塞
- 信号的阻塞是信号不会被递送给进程,信号忽略是信号已经递送达到,进程对信号的处理方式是忽略
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#define E_MSG(STRING, VAL) do{perror(STRING); return(VAL);}while(0)
void handle(int n){
printf("rev...%d\n", n);
}
int main(void){
// 阻塞解除以后,调用handle来处理信号
signal(2, handle);
signal(3, handle);
// 定义信号集类型的变量
sigset_t set, oldset;
// 初始化信号集set为空
sigemptyset(&set);
// 将2, 3, 9信号设置为进程信号的掩码集
sigaddset(&set, 2);
sigaddset(&set, 3);
sigaddset(&set, 9); // 即使这里阻塞了9号信号,用kill -9 pid 也还是能杀死这个进程
// 将信号集set设置为进程的信号掩码集, 并把之前的信号集保存到oldset
int sm = sigprocmask(SIG_SETMASK,&set, &oldset);
if(sm == -1)E_MSG("sigprocmask", -1);
sleep(5);
// 恢复原来的信号掩码集
sm = sigprocmask(SIG_SETMASK, &oldset, NULL);
if(sm == -1)E_MSG("sigprocmask", -1);
while(1);
return 0;
}
$ ./a.out
# 5s内发送多次2号信号和3号信号,会被阻塞
^C^C^C^\^\ ^\
# 5s后,恢复原来的信号掩码集不再阻塞2,3号信号
# 进程将会收到刚刚的2号和3号信号,但只会收到一次(2,3 都是不可靠信号)会有信号丢失
# 然后用handle函数来处理
rev...3
rev...2
# 然后再发送2, 3号信号给进程,都不再会被阻塞
^Crev...2
^Crev...2
^\rev...3
^\rev...3
- kill -9 这个进程也是能杀掉的,据说9号进程是穿甲弹
- 不可靠信号有信号的丢失,可靠信号没有信号的丢失。从1到31都是不可靠信号,34到64都是可靠信号。