Linux---阻塞信号

基本概念

信号递达(Delivery):实际执行信号的处理动作
信号的处理动作为:默认处理动作,忽略,用户自定义函数
信号未决(Pending):信号从产生到递达之间的状态
信号未决表示当前进程已经接受到了该信号,位图中该信号对应的bit位已经被置成了1。
在Linux下:普通信号在递达之前如果产生多次,只被记录一次,而实时信号在递达之前产生多次可以依次放在一个队列里
阻塞信号(Block):信号一但产生,就会被阻塞在未决状态,只有在接触阻塞后,该信号才会被递达
注意:阻塞和忽略是不一样的,只要信号被阻塞,它就不会被递达,而忽略是信号递达的一种方式

在内核中的表示

这里写图片描述

每个信号都有两个标志位分别表示阻塞(block)和未决(pending),还有一个函数指针表示处理动作。
信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清除该标志。
上图中:
1.SIGHUP信号未产生过,也没有被阻塞,所以block表和pending表中都未对该信号标志
2.SIGINT信号产生了,进程已经接受了该信号,但是该信号被阻塞了,block表和pending表都对其进行了标志,只有在阻塞解除后,操作系统才会在合适的时机对其进行处理。
3.SIGQUIT信号没有产生,但已经被阻塞,所以我们可以得出,并不是在信号产生后才能对其进行阻塞,而是在信号未产生时就会阻塞它,也就是一但SIGQUIT信号产生,它就会被阻塞在pending状态

signet_t 信号集类型

从上图我们可以看出,每个信号只有一个bit的未决标志和阻塞标志,非0即1,所以并不会记录其产生和阻塞的次数。因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储。sigset_t称为信号集,这个类型可以表示每个信号的“有效”和“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。
阻塞信号集也叫作当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解为阻塞而不是忽略
信号集操作函数

   #include <signal.h>                                                                                                               
   int sigemptyset(sigset_t *set);//初始化set指向的信号集,使其中所有信号对应的的bit位清零,表示该信号集不含任何有效信号
   int sigfillset(sigset_t *set);//初始化set指向的信号集,使其中所有信号对应的bit位置位,表示该信号集的有效函数包括系统支持的所有信号
   int sigaddset(sigset_t *set, int signo);//向信号集中添加某种有效信号
   int sigdelset(sigset_t *set, int signo);//删除信号集中对应的有效信号
   int sigismember(const sigset_t *set, int signo);//布尔函数,用于判断一个信号集的有效信号中是否包含某种信号,若包含则返回1,不包含返回0,出错返回-1
返回值:前四个函数都是成功返回0,出错返回-1

sigprocmask

  • 调用该函数可以读取或更改当前进程的信号屏蔽字(阻塞信号集)
   #include <signal.h>
   int sigprocmask(int how, const sigset_t *set, sigset_t *oset); 
返回值:成功返回0,出错返回-1
如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。
如果set是非空指针,则更改当前进程的信号屏蔽字,参数how指示如何更改
如果oset和set都是非空指针,则现将原来的信号屏蔽字备份到oset里,然后根据set和how参数更改当前信号屏蔽字。
假设当前信号屏蔽字为mask,下表说明了how参数如何指示修改
SIG_BLOCK set包含了我们希望添加到当前信号屏蔽字的信号,相当于mask=mask|set
SIG_UNBLOCK set包含了我们希望从当前信号屏蔽字中解除阻塞的信号,相当于mask=mask&~set
SIG_SETMASK 设置当前信号屏蔽字为set所指向的值,相当于mask=set

sigpending

   #include <signal.h>
   int sigpending(sigset_t *set);
读取当前进程的未决信号集,通过set参数传出。调用成功则返回0,出错则返回-1。

下面写一个小程序,显示当前进程的所有普通信号的未决状态

    #include <signal.h>                                                                                                             
    #include <stdio.h>

    void showpending(sigset_t *set)
    {
        int i = 0;
        for(i=1;i<32;i++)//从1号信号开始
        {
            if(sigismember(set,i))//判断指定信号是否在目标信号集中
                putchar('1');
            else
                putchar('0');
        }
        puts("");
    }
    int main()
    {
        sigset_t sig,pend;
        sigemptyset(&sig);
        sigfillset(&sig);
        sigaddset(&sig,2);//将2号信号作为有效信号添加进去
        sigprocmask(SIG_BLOCK,&sig,NULL);//添加2号信号到信号屏蔽字中,相当于阻塞2号信号
        while(1)
        {
            sigpending(&pend);//获取当前进程的未决信号集,用新定义的信号集类型pend接收
            showpending(&pend);//打印信号未决集
            sleep(1);//防止打印过快,结果不明显
        }
        return 0;
    }     

运行结果:
这里写图片描述
可以看到当我们在键盘按下Ctrl-C时,2号信号被标志为了1,说明此时2号信号被阻塞,一直处在未决状态
大家测试的时候不要弄死循环了,还得再开一个终端用kill命令杀死进程才行

猜你喜欢

转载自blog.csdn.net/it_xiaoye/article/details/79981510
今日推荐