阻塞信号及相关函数

26 篇文章 0 订阅
19 篇文章 0 订阅

阻塞信号

先来看一下几个常见的信号相关概念

1实际执行信号的处理动作称为信号递达。
2 信号从产生到递达之间的状态称为信号未决。
3进程可以选择阻塞某个信号。
4被阻塞的信号产生时将一直保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。
5注意:阻塞和忽略是不同的,只要信号被阻塞就永远不会被递达,而忽略就是在递达之后,可选择的一种处理动作。

在内核中的表示示意图
这里写图片描述
每个信号都有两个标志位分别表示阻塞和未决,还有一个函数指针表示处理动作,信号产生时,内核在进程控制块中设置该信号的未决标志(将0置为1说明该信号产生了),知道信号递达才清出该标志(将1置为0)。由上图来说:
SIGHUP信号没有被阻塞(block表中对应的位是0)
也没有产生该信号(pending表中对应的位是0)
如果这个信号产生了并且被递达那么他的处理动作是默认处理动作(handler表中对应的位是SIG_DFL)

SIGINT信号被阻塞(block表中对应的位是1)
并且产生了(pending表中对应的位是1)这个信号(这个时候该信号会一直处于未决状态)
如果这个信号产生了并且被递达那么他的处理动作是忽略(handler表中对应的位是SIG_IGN)
多说一句:虽然处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍然有可能在修改了处理动作之后再解除阻塞。

SIGQUIT信号被阻塞(block表中对应的位是1)
未产生该信号(pending表中对应的位是0)
如果这个信号产生了并且被递达那么他的处理动作是用户自定义的处理动作(handler表中对应的位是User Space)

sigset_t
每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t叫做信号集,这个类型可以表示每个信号的有效或无效状态,在阻塞信号集中有效和无效的含义是该信号是否被阻塞,在未决信号集中表示的是该信号是否被产生过(即是否处于未决状态)。阻塞信号集也叫作当前进程的信号屏蔽字,这里的屏蔽应理解为阻塞而不是忽略。

信号集操作函数

我们必须通过调用信号集操作函数来操作sigset_t变量。

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

sigprocmask
调用该函数可以读取或更改进程的信号屏蔽字(阻塞信号集)

#include<signal.h>
int sigprocmask(int how,const sigset_t *set,sigset_t *oset);
成功返回0,出错返回-1

如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非空指针,则更改进程的信号屏蔽字,参数how如何更改。若set与oset都为非空指针,则先将原来的信号屏蔽字备份到oset里,然后根据how和set参数修改信号屏蔽字,假设当前信号屏蔽字mask,下面说明how参数的可选值:
SIG_BLOCK:*set包含了我们希望添加到当前信号屏蔽字*的信号,相当于mask=mask|set
SIG_UNBLOCK:*set包含了我们希望从当前信号屏蔽字中解除阻塞*的信号,相当于mask=mask&~set。
SIG_SETMASK:设置当前信号屏蔽字为set所指向的值,相当于mask=set

如果调用sigprocmask解除了对当前若干个未决信号的阻塞,则在sigprocmask返回前,至少将其中一个信号递达。

sigpending

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

简单的小应用:

#include<stdio.h>
#include<signal.h>
#include<unistd.h>
void printsigset(sigset_t *set)
{
    int i = 0;
    //循环依次判断i号信号是否为有效信号
    for(;i < 32;i++)
    {
        if(sigismember(set,i))
        {
            //如果是有效信号则输出1
            putchar('1');
        }
        else
            //不是有效信号输出0
            putchar('0');
    }
    puts("");
}
int main()
{
    //定义两个信号集
    sigset_t s,p;
    //将信号集s初始化,即使其中所有的信号对应的bit位置为0,表示该信号机不包括任何有效信号
    sigemptyset(&s);
    //将SIGINT信号在信号集s中设置为有效信号
    sigaddset(&s,SIGINT);
    //调用sigprocmask函数,更改信号屏蔽字
    //将信号集s中的有效信号添加到当前进程的阻塞信号集
    //即将SIGINT信号阻塞
    sigprocmask(SIG_BLOCK,&s,NULL);
    while(1)
    {
        //调用sigpending函数读取当前进程的未决信号集,通过p参数传出
        sigpending(&p);
        //调用printsigset函数每隔1秒打印当前进程的未决信号集
        printsigset(&p);
        sleep(1);
    }
    return 0;
}

程序运行的时候我们按下Ctrl+c产生一个SIGINT 信号,但是该信号被阻塞了,所以就会一直处于未决状态,但是SIGQUIT信号并没有被阻塞,因此我们按下Ctrl+\依旧可以终止程序的运行。
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值