本文主要简单介绍下linux下信号的阻塞,解除阻塞并递达。
先介绍下相关概念:
信号递达(Delivery):实际执行信号的处理动作 ,
有3种状态:
1.忽略
2.执行默认操作(一般为终止进程)
3.自定义动作(信号的捕捉)
信号未决(Pending):信号从产生到递达之间的状态 (在这里信号可以被阻塞(Block))
信号阻塞(Block):将信号保持在未决状态,直到被解除阻塞之后,才执行递达动作
另外讲一下
阻塞与忽略的区别:忽略是信号递达的一种(处理动作),阻塞直到被解除才能执行递达动作(在信号未决中,信号递达前)
1.block表:进程的信号屏蔽字。由4个字节的位图表示,每个比特位对应一个的信号,比特位是0时表示该信号没被阻塞,为1时表示信号被阻塞
2.penging表:用于描述一个进程是否收到信号。也是由4个字节的位图表示,每个比特位对应一个信号,此时比特位的值可以为0或1,当其中一个比特位为0时,表示该进程没有收到操作系统发给他的信号,而其中一个比特位为1时表示收到了操作系统给他发送的信号。而此时要做出判断如果block表中与他相同的比特位此时如果为0,则此信号可以被未决,而如果blcok表中与他对应的比特位为1,则表示此信号被阻塞不能被未决。
3.handler表(函数指针数组):信号的处理方式。
常见信号集函数
#include<signal.h>
int sigemptyset(sigset_t *set); // 初始化set所指的信号集,其中所有信号的对应bit清空,全部设为无效
int sigfillset(sigset_t *set); //初始化set,全部设为有效
int sigaddset(sigset_t *set, int signo); //信号集中添加某种有效信号
int sigdelset(sigset_t *set, int signo); //信号集中删除某种有效信号
//这四个函数都是成功返回0,出错返回-1
int sigismember(const sigset_t *set, int signo);
//判断一个信号集的有效信号中是否包含某种信号。包含则返回1,不包含则返回0,出错返回-1
sigprocmask
#include<signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
功能:修改block表,进行读取或更改进程的信号屏蔽字
返回值:若成功则为0,若出错则为-1
参数说明:
how:修改方式;
oset:备份原来的信号屏蔽字;
set: 更改进程的信号屏蔽字。
注意:如果调用sigprocmask解除了对当前若干个未决信号的阻塞,则在sigprocmask返回前,至少将其中一个信号递达。
sigpending
#include<signal.h>
int sigpending(sigset_t *set);
功能:进行读取进程的未决信号集
返回值:成功返回0,出错返回-1
代码
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void printsig(sigset_t* set){
int i=1;
for(;i<=31;i++){
if(sigismember(set,i)){
printf("1");
}else{
printf("0");
}
}
printf("\n");
}
void handler(int sig)
{
if (sig == SIGINT)
printf("recv a sig=%d\n", sig);
}
int main()
{
sigset_t block,oblock,pending;
sigemptyset(&block); //clear and init
sigemptyset(&oblock);
sigaddset(&block,2); //2 signal
signal(2, handler);
sigprocmask(SIG_BLOCK,&block,&oblock); //set block sigset_t
int count=0;
while(1){
sigpending(&pending); //get pending
printsig(&pending);
if(count++>5){
printf("recover sig!\n");
sigprocmask(SIG_SETMASK,&oblock,NULL);
}
sleep(1);
}
return 0;
}
结果
开始之前pending表为空,因此输出的的结果为全0,程序首先将SIGINT信号加入进程阻塞集(屏蔽集)中,一开始并没有发送SIGINT信号,所以进程未决集中没有处于未决态的信号,当我们按下ctrl+c时,向进程发送SIGINT信号,由于SIGINT信号处于进程的阻塞集中,所以发送的SIGINT信号不能递达,也是就是处于未决状态,所以当我打印未决集合时发现SIGINT所对应的位为1,当达到count>5时,进程阻塞被解除,所以信号直接递达,执行对应的处理函数,最后打印之后pending表又变为全0状态,按Ctrl-\仍然可以终止程序,因为SIGQUIT信号没有阻塞。