当前位置: 首页 > article >正文

【信号】信号的保存

信号的保存 

信号其他相关常见概念

实际执行信号的处理动作称为信号递达(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号信号你无法设置屏蔽,和自定义捕捉一样 


http://www.kler.cn/a/301203.html

相关文章:

  • PHP开发全新UI多语言多商户跨境商城源码、支持一键铺货、一键下单
  • 【c++丨STL】list的使用
  • 基本数据类型:Kotlin、Dart (Flutter)、Java 和 C++ 的比较
  • RPA真的是人工智能吗?
  • 云原生周刊:Kubernetes v1.32 要来了
  • java itext后端生成pdf导出
  • ffmpeg面向对象-rtsp拉流相关对象
  • 为什么不写注释?写“为什么不”注释?
  • pdf删除一页怎么删除?5种方法详细讲解,pdf删除页面实用技巧分享!
  • 【iOS】push和present的区别
  • echarts 多个3D柱状图
  • Python爱心射线(完整代码)
  • git一个项目关联多个远程仓库
  • android 权限说明
  • Parasoft如何助力AUTOSAR C++合规测试
  • 力扣322-零钱兑换(Java详细题解)
  • 开源网安斩获CCIA中国网络安全创新创业大赛总决赛三等奖
  • iOS 18 RC 版本更新,为相机应用引入了“暂停录制视频”功能
  • 滑动窗口——优选算法
  • MySQL主从同步延时高问题排查
  • 省市县相关校验sql随笔
  • 建筑物检测系统源码分享
  • linux内核驱动:ptp内核phc框架
  • rman compress
  • starrocks结合同步和异步物化视图建立数据湖和数据仓库
  • java的ReentrantLock原理