【信号】信号的保存

信号的保存 

信号其他相关常见概念

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

进程在接收到信号之后,可能不处理,那么信号就会保存,等到合适的时候再进行处理,一般这个信号会保存在一张位图里,这个位图是进程PCB 的一部分,比特位的0和1代表信号是否收到,比特位的位置代表第几号信号,所谓保存信号就是修改这张位图的内容,OS是进程的管理者,它才有资格修改这张位图的内容

OS提供了三张表,block表,pending表,handler表

block表:比特位的位置代表第几号信号,内容代表该信号是否被阻塞,例如,第二个比特位的内容是1 ,代表第2号信号被阻塞

pending表:就是信号保存的表,信号没有被处理时就保存在这张表里

handler表:函数指针数组,保存的是函数方法的地址,有3种,SIG_DFL是终止处理,SIG_IGN是忽略处理,最后一个是自定义处理

每个信号都有两个标志位分别表示阻塞(block)和未决(pending),还有一个函数指针表示处理动作。信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清除该标志。

sigset_t类型

如果你要修改这些位图的内容,肯定是不行的,你没有权限,OS才有,所以为了让我们更好的访问到这些位图并修改,OS提供了sigset_t类型,它的底层其实就是位图

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

sigset_t操作函数

sigset_t类型对于每种信号用一个bit表示“有效”或“无效”状态,至于这个类型内部如何存储这些bit则依赖于系统实现,从使用者的角度是不必关心的,使用者只能调用以下函数来操作sigset_ t变量,而不应该对它的内部数据做任何解释,比如用printf直接打印sigset_t变量是没有意义的

函数sigemptyset:初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含 任何有效信号。
函数sigfillset:初始化set所指向的信号集,使其中所有信号的对应bit置位,表示该信号集的有效信号包括系统支持的所有信号。
注意,在使用sigset_ t类型的变量之前,一定要调 用sigemptyset或sigfillset做初始化,使信号集处于确定的状态。

初始化sigset_t变量之后就可以在调用sigaddsetsigdelset在该信号集中添加或删除某种有效信号

这四个函数都是成功返回0,出错返回-1。

函数sigismember:是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种信号,若包含则返回1,不包含则返回0,出错返回-1

sigprocmask函数

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

如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改。如果oset和set都是非空指针,则先将原来的信号 屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。

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

sigpending函数

读取当前进程的未决信号集,通过set参数传出。调用成功则返回0,出错则返回-1。

函数运用例子 

思路:

1.对2号信号进行屏蔽

2.重复打印pending表

3.几秒后解除对二号信号的屏蔽

4.运行程序,发送信号,观察现象

代码:

#include<iostream>
#include<signal.h>
#include<unistd.h>
using namespace std;


void Printpending(sigset_t& pending)
{
    for(int signo=31;signo>=1;signo--)
    {
        if(sigismember(&pending,signo)) cout<<'1';
        else cout<<'0';
    }
    cout<<endl;
}
int main()
{
    //1.先对2号信号进行屏蔽
    //1.1  数据储备
    sigset_t bset,oset;// 在哪里开辟的空间???用户栈上的,属于用户区
    sigemptyset(&bset);
    sigemptyset(&oset);

    sigaddset(&bset,2);//我们已经把2号信号屏蔽了吗?  其实没有,并没有设置到系统的block表里
    //1.2调用系统调用,把2号信号屏蔽弄进内核里
    sigprocmask(SIG_SETMASK,&bset,&oset);

    //2.重复打印pending表
    sigset_t pending;
    int cnt=0;
    while(true)
    {
        //2.1获取pending表
        int n=sigpending(&pending);
        if(n<0) continue;
        //2.3打印pending表
        Printpending(pending);
        cnt++;
        sleep(1);
        if(cnt==6)
        {
            //2.3解除对二号信号的屏蔽
            cout << "unblock 2 signo" << endl;
            // sigdelset(&bset,2);
            // sigprocmask(SIG_SETMASK,&bset,&oset);

            //或者这样
            sigprocmask(SIG_SETMASK,&oset,nullptr);   //oset保存的是上一次的block表

        }
    }
     //3.发送信号

    return 0;
}

结果:

注意:不是所以得信号都可以被屏蔽,9和19号信号你无法设置屏蔽,和自定义捕捉一样 

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱敲代码的柯基

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值