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

【信号】信号的保存

信号的保存 

信号其他相关常见概念

实际执行信号的处理动作称为信号递达(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.mrgr.cn/news/25375.html

相关文章:

  • 杂七杂八-系统环境安装
  • 保姆级离线+windows环境+大模型前端UI安装(二)
  • 240416 初始化列表 构造与隐式类型转换 static成员 友元 内部类
  • 专业版PyCharm使用plt.show()显示图像时,如何不显示在右侧工具栏中,而是直接弹出来
  • RTL设计中中$signed函数的使用
  • 海外仓系统如何为企业提供智能财务解决方案?
  • 严重干扰的验证码识别系统源码分享
  • 工具使用记录-Tkinter
  • Rust:Result 和 Error
  • el-input 只能输入数字和一个小数点,或者只能输入两位小数
  • 线程---实践与技巧(C语言)
  • 线程池的应用-->2
  • 职场效率提升秘籍
  • 合成控制法SCM
  • CSS——盒子模型
  • 数据处理与统计分析篇-day02-Linux进阶
  • 山峰个数【python实现】
  • 未来工业,新质赋能!迈威通信邀您共赴智造盛宴
  • C++多态讲解
  • 「漏洞复现」SPIP porte_plume插件 远程代码执行漏洞(CVE-2024-7954)