news 2026/5/17 2:47:20

【Linux】不允许你还不会——信号保存(3)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Linux】不允许你还不会——信号保存(3)

问题:信号为什么要被保存?

答:信号不会立即处理,产生之后,处理之前,就有时间窗口保存信号,必须要把信号保存起来,方便后面进行处理。

概念:

1)实际执行信号的处理动作称为:信号递达(handler)

2)信号从产生到递达之家的状态称为:信号未决(pending)

3)信号可以选择阻塞(block)某个信号;说人话就是:保存该信号,但是不进行处理

4)被阻塞的信号产生时将保持在未决状态,直到进程解除对该信号的阻塞才执行递达的动作

注意:阻塞和忽略不同,只要信号被阻塞就不会递达,而忽略是递达之后可选的一种处理动作

pending 表:这张表其实就是一个long long 类型,只不过用位图操作来表示普通信号【1,31】(实际是【1,64】,因为还有实时信号)是否被保存,比特位的位置:信号编号,比特位的内容:是否保存(0:没有,1:是);

block 表:这张表和 pending 表一样,也是位图操作原来表示普通信号 【1,31】是否被阻塞,比特位的位置:信号编号,比特位的内容:是否被阻塞(0:没有,1:是);

handler 表:这张表是函数指针数组,专门保存对应的信号编号的处理函数,下标 + 1 = 信号编号

问题:signal(2,myhandle) 底层会做些什么?

答:把我们 myhandle 函数地址根据信号编号 2 来填写到对应的 handler 表里。

问题:什么叫忽略,默认?

答:我们使用 signal 函数时,传宏来表示对应的忽略和默认:SIG_DFL 和 SIG_IGN ,他们两个的本质其实就是 0 和 1 数字,只不过把他们强转成函数类型,通过对比得出他们是自定义函数(函数指针较长)还是忽略和默认。

问题:在信号还没有产生的时候,进程就能识别和处理信号了,因为:程序员已经内置对应管理和处理方法,其实就是上面那三张表。

结论:OS 需要让用户控制信号,本质就是访问和操作上面的三张表,因为那三张表数据内核结构,所以我们要使用系统调用来操作这个三张表,其中:handler 表系统调用:signal ,block:

pending 表:

这些系统调用函数除了 signal 都是可以获取和设置当前进程的 pending 表和 block 表的。

上面的两个函数都有一个参数:sigset_t 类型,这个内核自定义的类型,它其实和pending 和 block 表里的 long long 类型一样都是用来表示信号是否被保存/阻塞,通过它可以获取到对应的表;其中 sigset_t 称为:信号集,block表称为 block 信号集、pending 表称为:pending 信号集。

其中,阻塞信号集称为:信号屏蔽字(Signal Mask)。

注意:Sigal Mask 类似于 umask 权限掩码。

不建议我们用户是直接修改表中的数据,而是使用系统调用来修改:

这些系统调用这里就不再多讲,如果想了解可以问一下大模型。

sigprocmask 系统调用可以读取或更改进程的信号屏蔽字:

第一个参数:

第二个参数:传你要修改的屏蔽字

第三个参数:原来的的屏蔽字,防止你要恢复原来的屏蔽字。

返回值:成功 0 ,失败:-1

sigpending 系统调用,它可以获取 pending 表

参数:传一个 pending 表的指针过去。

返回值:成功0,失败:-1

sigpending 系统调用可以获取 pending 表,那么谁来修改他呢?

答:我们用户使用 kill 函数或者命令来让 OS 来修改。

#include <iostream> #include <unistd.h> #include <signal.h> void printpending(const sigset_t& pending) { for(int signo = 31;signo > 0;signo--) { if(sigismember(&pending,signo))//判断 signo 信号是否存在, { std::cout << "1"; } else std::cout << "0"; } std::cout << std::endl; } int main() { //屏蔽2号信号 sigset_t block_set,old_set; sigemptyset(&block_set);//初始化 sigemptyset(&old_set);//初始化 sigaddset(&block_set,SIG_SETMASK);//对我们自定义的位图进行屏蔽 2号信号 的操作:0 ——> 1,到这里我们还没有对当前进程的 2号信号进行屏蔽 int n = sigprocmask(SIG_SETMASK,&block_set,&old_set);//修改内核级的 block 表,此时已经把 2号信号 屏蔽了 (void)n; std::cout << "pid:" << getpid() << std::endl; int cnt = 1; //获取 pending 表和打印这个表 while(true) { sigset_t pending; sigemptyset(&pending);//初始化 n = sigpending(&pending);//获取 pending 表 printpending(pending); if(cnt == 20)//解除对 2号信号的屏蔽 { std::cout << "解除对2号信号的屏蔽" << std::endl; int n = sigprocmask(SIG_SETMASK,&old_set,nullptr);//把老的 block 表放回去就相当于解除对2号信号的屏蔽 } cnt++; sleep(1); } return 0; }

#include <iostream> #include <unistd.h> #include <signal.h> void handl(int signo) { std::cout << "处理完成:" << signo << std::endl; } void printpending(const sigset_t& pending) { for(int signo = 31;signo > 0;signo--) { if(sigismember(&pending,signo))//判断 signo 信号是否存在, { std::cout << "1"; } else std::cout << "0"; } std::cout << std::endl; } int main() { signal(2,handl);//更改2号信号的处理函数 //屏蔽2号信号 sigset_t block_set,old_set; sigemptyset(&block_set);//初始化 sigemptyset(&old_set);//初始化 sigaddset(&block_set,SIG_SETMASK);//对我们自定义的位图进行屏蔽 2号信号 的操作:0 ——> 1,到这里我们还没有对当前进程的 2号信号进行屏蔽 int n = sigprocmask(SIG_SETMASK,&block_set,&old_set);//修改内核级的 block 表,此时已经把 2号信号 屏蔽了 (void)n; std::cout << "pid:" << getpid() << std::endl; int cnt = 1; //获取 pending 表和打印这个表 while(true) { sigset_t pending; sigemptyset(&pending);//初始化 n = sigpending(&pending);//获取 pending 表 printpending(pending); if(cnt == 20)//解除对 2号信号的屏蔽 { std::cout << "解除对2号信号的屏蔽" << std::endl; int n = sigprocmask(SIG_SETMASK,&old_set,nullptr);//把老的 block 表放回去就相当于解除对2号信号的屏蔽 } cnt++; sleep(1); } return 0; }

结论:一旦我们解除对某个信号的阻塞,该信号就会立即被处理。一旦处理完该函数,此时pending 表对应的某个信号的比特位由 1 ——> 0

问题:解除某个信号的屏蔽之后,是先进行 pending 表中对应的信号由 1—> 0 ,还是先执行处理函数?

答:先把 pending 表中对应的信号由 1—> 0 ,再执行对应的处理函数。


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/10 19:26:02

Dify平台API权限控制机制的设计与实施

Dify平台API权限控制机制的设计与实施 在AI应用快速渗透企业核心业务的今天&#xff0c;一个看似不起眼的技术细节——API能不能被随意调用——往往决定了整个系统的安危。设想一下&#xff1a;某天你发现外部合作伙伴通过一个公开的接口&#xff0c;不仅调用了你的智能客服模型…

作者头像 李华
网站建设 2026/5/16 16:51:24

LobeChat能否实现多人协同编辑?共享会话功能设想

LobeChat能否实现多人协同编辑&#xff1f;共享会话功能设想 在远程办公常态化、AI助手深度融入工作流的今天&#xff0c;一个看似简单却日益凸显的问题浮出水面&#xff1a;我们能否像协作编辑一份文档那样&#xff0c;多人实时共用同一个AI对话&#xff1f; 想象这样一个场…

作者头像 李华
网站建设 2026/5/11 18:06:11

基于单片机的智能温控风扇系统设计(温度+风速调节)【附代码】

&#x1f4c8; 算法与建模 | 专注PLC、单片机毕业设计 ✨ 擅长数据搜集与处理、建模仿真、程序设计、仿真代码、论文写作与指导&#xff0c;毕业论文、期刊论文经验交流。✅ 专业定制毕业设计✅ 具体问题可以私信或查看文章底部二维码本系统的核心设计内容在于构建一个以单片机…

作者头像 李华
网站建设 2026/5/11 17:08:02

Python中配置TensorFlow-GPU的完整方法

Python中配置TensorFlow-GPU的完整方法 在深度学习项目开发中&#xff0c;模型训练动辄需要数小时甚至数天&#xff0c;而能否充分利用GPU资源&#xff0c;往往决定了整个研发流程的效率。如果你还在用CPU跑ResNet或Transformer&#xff0c;那可能连一个epoch都坚持不下来就放…

作者头像 李华
网站建设 2026/4/30 5:34:00

基于单片机的智能晾衣架控制系统设计【附代码】

&#x1f4c8; 算法与建模 | 专注PLC、单片机毕业设计 ✨ 擅长数据搜集与处理、建模仿真、程序设计、仿真代码、论文写作与指导&#xff0c;毕业论文、期刊论文经验交流。✅ 专业定制毕业设计✅ 具体问题可以私信或查看文章底部二维码在智能晾衣架控制系统的核心控制单元与驱动…

作者头像 李华
网站建设 2026/5/15 8:19:23

SP40P65NJ:一款高性能40V P沟道MOSFET深度解析

在电源管理与DC-DC转换器设计中&#xff0c;MOSFET的选择直接影响系统的效率、可靠性与成本。今天我们将推出的一款40V P沟道MOSFET——SP40P65NJ&#xff0c;结合其官方规格书&#xff0c;从关键参数、性能特点到封装信息进行全面梳理。一、核心规格摘要参数典型值条件漏源击穿…

作者头像 李华