信号屏蔽(pending)

本文主要简单介绍下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信号没有阻塞。

猜你喜欢

转载自blog.csdn.net/qiting00/article/details/73718559
今日推荐