【Linux】详解信号的保存信号屏蔽字的设置

news/2024/9/19 15:11:08/ 标签: 服务器, 网络, linux, 后端, c++, 信号处理, 信息与通信

一、信号处理的一些常见概念

  • 实际执行信号的处理动作称为信号递达(Delivery)。
  • 信号从产生到递达之间的状态,称为信号未决(Pending)。
  • 进程可以选择阻塞 (block )某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。
  • 注意:阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。
  • 阻塞一个信号和是否收到这个信号是没有关系的。也就是说,在还没收到一个信号之前就可以在内核中设置对这个信号进行阻塞。

 二、信号保存以及阻塞的内核级理解

在进程的PCB中,其实是有三张表。

        一张为block位图(阻塞位图),也就是一个32位的整形变量,其中取高31位来表示是否阻塞对应的信号,比如说block位图中第0个比特位不用,第1个比特位表示是否阻塞1号信号,第一个比特位为1就表示阻塞1号信号,为0就表示不阻塞1号信号,依次类推,第2到第31个比特位也是同样的道理。

        一张为pending位图(未决位图),也是一个32位的整形变量,其中取高31位来表示是否收到对应的信号,比如说pending位图中第0个比特位不用,第1个比特位表示是否收到1号信号,第一个比特位为1就表示收到1号信号,为0就表示没有收到1号信号。

        另一张是一个函数指针数组,该数组中每一个下标中都存放了收到对应信号后的处理方法。如果我们不对方法做自定义写入,那么进程在收到对应信号后执行的就是默认的方法,如果自定义写入了那执行的就是我们写入的方法。

        在上图中,三个数组(前两张位图也可以看成数组)应该横着看,依次表示该信号是否被阻塞,是否收到该信号,以及执行该信号的处理方法。 常规信号在递达之前产生多次只计一次,也就是说,当在一段时间内有多个相同的信号到来但却来不及被处理时,在pending位图里只会记录一次而实时信号在递达之前产生多次可以依次放在一个队列里。

三、查看pending位图

        其中sigset_t类型的解释就在下面,set为一个输出型参数,我们传入一个sigset_t类型的参数set,pending位图中的值就被set参数获得了。如果获取成功sigpending函数返回0,是被返回-1。

四、设置信号屏蔽字操作(修改block位图)

        从上面的介绍中我们也可以看到,其实block位图和pending位图的结构是十分相似的,所以未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,可以用来修改进程block位图中的信号屏蔽字sigset_t就是一种数据类型,跟int、double这些数据类型没有区别。

3.1、信号集操作函数

        sigset_t虽然是一种数据类型,但是我们并不能直接手动的修改sigset_t类型的值,必须要调用对应的系统调用函数。

#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset (sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);
  • sigemptyset:初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含任何有效信号。
  • sigfillset:初始化set所指向的信号集,使其中所有信号的对应bit置1位,表示该信号集的有效信号包括系统支持的所有信号。
  • sigaddset:在set信号集中添加signo信号。
  • sigdelset:在set信号集中删除signo信号。
  • sigismember:用于测试一个指定的信号是否已加入至一个特定的信号集中。

        我们设置完信号集set的值后,set并没有被设置进进程的PCB中,还需要我们调用系统调用函数设置。 

 3.2、设置信号屏蔽字

利用sigprocmask系统调用函数可以设置进程的信号屏蔽字

第一个参数how有三个选项:

  • SIG_BLOCK:set包含了我们希望添加到当前信号屏蔽字中的信号,相当于mask=mask|set。
  • SIG_UNBLOCK:set包含了我们希望从当前信号屏蔽字中解除阻塞的信号,相当于mask=mask&~set。
  • SIG_SETMASK:设置当前信号屏蔽字为set所指向的值,相当于mask=set。

        第二个参数set是我们设置的信号屏蔽字,第三个参数为输出型信号屏蔽字,是原来的信号屏蔽字。 

3.3、设置信号屏蔽字的例子

        下面是一个设置屏蔽2号信号,有解除屏蔽2号信号的例子。在程序运行起来到程序运行到20秒期间,我给程序发送2号信号,应该看到pending位图中2号信号的位置为1但程序不退出,到了20秒时程序退出。

        下面是打印pending表的函数,如果收到信号,对应的比特位就置1,如果没有收到就置0。

void print(const sigset_t& pending)
{for(int i = 31; i>=1; i--){if(sigismember(&pending, i))std::cout << "1";elsestd::cout << "0";}std::cout << std::endl;
}

 2号信号加入到信号屏蔽集中:

    sigset_t set, oldset;sigemptyset(&set);sigemptyset(&oldset);sigaddset(&set, 2);//将2号信号加入到要屏蔽的信号集中

 set设置进进程的PCB中:

    //设置set进block位图中int n = sigprocmask(SIG_SETMASK, &set, &oldset);if(n == -1){std::cout << "设置屏蔽字错误!" << std::endl;return 1;}

查看pending表,观察退出状态:

    int cnt = 0;//查看pending位图,给进程发送2号信号,pending位图中应该出现2号信号,但是进程不会退出//等到20秒时程序退出while(true){cnt++;if(cnt == 20)sigprocmask(SIG_UNBLOCK, &set, &oldset);sigset_t pending;sigemptyset(&pending);int m = sigpending(&pending);print(pending);sleep(1);}

发送2号信号,程序到20秒时退出: 

四、总结

        31个信号中并不是所有信号都可以被屏蔽掉,9号信号(SIGKILL)和19号信号(SIGSTOP)是无法被屏蔽掉的。若想获取上述的完整的代码,请移步本人码云:240427 · 沈旭彬/C++代码 - 码云 - 开源中国 (gitee.com) 


http://www.ppmy.cn/news/1450235.html

相关文章

uniapp+vue社区车位预订租赁系统 微信小程序

本私家车位共享系统有管理员&#xff0c;用户两个角色。管理员可以对用户信息&#xff0c;车辆类型信息进行管理&#xff0c;并且可以审核用户提交的租赁订单&#xff0c;用户可以注册登录&#xff0c;新增车辆信息&#xff0c;查看车位信息并且租赁&#xff0c;并且可以支付。…

《在合适的地方使用设计模式》

本文章属于专栏- 概述 - 《设计模式&#xff08;极简c版&#xff09;》-CSDN博客 计算系统&#xff0c;是物理世界的一部分。各行各业的历史经验告诉我们&#xff0c;没有一劳永逸&#xff0c;一成不变的模式&#xff0c;而软件系统的设计模式也一样。要正确地使用一个…

CentOS8 安装ansible

CentOS8 无法使用yum进行ansible安装&#xff0c;此次使用pip install ansible来安装ansible 大概步骤 1&#xff0c;编译安装升级python&#xff0c;centos8系统自动安装的python3.6版本过低&#xff0c;安装ansible时会有警告 2&#xff0c;安装pip 3&#xff0c;pip install…

Stable Diffusion WebUI 中文提示词插件 sd-webui-prompt-all-in-one

本文收录于《AI绘画从入门到精通》专栏,订阅后可阅读专栏内所有文章,专栏总目录:点这里。 大家好,我是水滴~~ 今天为大家介绍 Stable Diffusion WebUI 的一款中文提示词插件 sd-webui-prompt-all-in-one,就像它的名字一样,该插件几乎涵盖了提示词相关的所有功能。 文章内…

富格林:可信方略杜绝交易虚假

富格林指出&#xff0c;黄金市场是一个极具诱惑力的市场&#xff0c;它是在一个大家共同认可的游戏规则下&#xff0c;凭借自己可信的决策、判断来进行交易的一种投资市场。黄金市场不断有新手投资者的加入&#xff0c;但是要真正在该市场上获利&#xff0c;杜绝虚假套路是一个…

windows驱动开发-电源状态(二)

Modern Standby这个特性其实很难准确的讲清楚&#xff0c;因为它是一个系统行为不是驱动功能行为&#xff0c;应用层、功能驱动、系统总线、设备本身都有不同程度的参与&#xff0c;并且它属于否决性的&#xff0c;一个系统中&#xff0c;只要有一个设备不支持Modern Standby&a…

macos vscode 激活虚拟环境

用 source activate activate的路径报错 解决&#xff1a;cd到activate下的文件下 直接source activate 解决 (base) dearrdearrdeMacBook-Air 时序作业 % /Applications/文件/派森/时序作业/.venv/bin/activat zsh: no such file or directory: /Applications/文件/派森/时…

linux 开机自启 rc.local

rc.local 是启动加载文件 例1. compose启动Harbor 写一个开启自动启动的脚本 [rootharbor harbor]# vim startall.sh #!/bin/bash cd /root/harbor docker-compose stop && docker-compose start给脚本权限 chmod x startall.sh chmod x /etc/rc.d/rc.local #ll 查…

R语言的学习—5—多元数据直观表示

1、数据读取 ## 数据整理 d3.1read.xlsx(adstats.xlsx,d3.1,rowNamesT);d3.1 #读取adstats.xlsx表格d3.1数据 barplot(apply(d3.1,1,mean)) #按行做均值条形图 barplot(apply(d3.1,1,mean),las3) barplot(apply(d3.1,2,mean)) #按列做均值图条形图 barplot(a…

【网络通信】Windows搭建RTMP视频流服务器(含推流/拉流详细教程)

RTMP&#xff08;Real-Time Messaging Protocol&#xff09;是一种用于实时流媒体传输的网络协议&#xff0c;主要用于传输音频、视频和数据。RTMP最初是由Adobe Systems公司开发的&#xff0c;用于其Flash平台和Adobe Media Server&#xff0c;但随着技术的发展和开源社区的推…

前端工程化的基本介绍

文章目录 一、概念二、前端工程化的细节模块化组件化规范化 一、概念 工程化&#xff0c;可以理解为使用一些方式&#xff0c;去改良提高行业中现有的步骤、设计、应用方式。前端工程化&#xff0c;就是指对前端进行一些流程的标准化&#xff0c;让开发变得更有效率&#xff0…

C# Solidworks二次开发:枚举应用实战(第十一讲)

大家好&#xff0c;今天继续介绍我们的枚举应用系列。 下面是今天要介绍的枚举值&#xff1a; &#xff08;1&#xff09;第一个为swsPVResultCombinationError_e&#xff0c;这个枚举值的含义为结合压力容器设计研究结果时的错误&#xff0c;下面是官方的具体枚举值&#xf…

为何软件IT行业重视创新而不是稳定?

为何软件IT行业重视创新而不是稳定&#xff1f;用户为此受苦&#xff1a;用户体验差&#xff01; 彼得-蒂尔有一句名言&#xff1a;"竞争是失败者的事"。 如果没有必要&#xff0c;就不要把自己置于被迫竞争的境地。 我给年轻程序员的建议是&#xff0c;如果你想创…

Java学习第02天-类型转换、运算符

目录 类型转换 自动类型转换 表达式的自动类型转换 强制类型转换 运算符 基本运算符 案例解答 连接字符串 自增自减运算符 面试习题 赋值运算符 比较运算符 逻辑运算符 基本逻辑运算符 短路逻辑运算符 三元运算符 基础知识 拓展案例 运算符优先级 读取用户…

ffmpeg 转换es流成为ps流

目的是将es流转换成为ps流 写入到文件中 #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> #include <libavutil/avutil.h> #include <libavutil/timestamp.h>int main(int argc, char** argv) {const char* input_filename &qu…

[随记]Mac安装Docker及运行开源Penpot

下载Docker Desktop for Mac&#xff1a;https://www.docker.com/products/docker-desktop/ 安装Docker Desktop for Mac&#xff0c;安装完成后&#xff0c;启动Docker&#xff0c;然后在终端输入&#xff1a; docker version 在Mac电脑的Desktop&#xff0c;随便创建一个文…

什么是oneflow

一&#xff0c;什么是OneFlow&#xff1f; OneFlow是一个用于机器学习的开源软件框架&#xff0c;它允许研究人员和开发人员设计、训练和部署机器学习模型。机器学习是人工智能的一个分支&#xff0c;它使计算机能够从数据中学习并做出预测或决策&#xff0c;而不需要明确编程…

由混淆依赖所引起的RCE

正文 正常情况下 在一个正常的开发和部署环境中&#xff0c;package.json 文件和相关脚本被用来管理项目依赖、定义项目设置以及执行常规的构建或部署任务。一个典型的正常请求过程可能如下&#xff1a; 1.安装依赖&#xff1a; #现代有很多人用yarn,pnpm等替代npm,不管怎么…

社交媒体数据恢复:TT语音

TT语音数据恢复方法 1. 恢复聊天记录 如果您的TT语音聊天记录丢失&#xff0c;可以通过以下步骤尝试恢复&#xff1a; 登录TT语音&#xff1a;首先&#xff0c;您需要登录您的TT语音账户。如果您忘记了密码&#xff0c;可以通过点击登录页面的“忘记密码”链接&#xff0c;然…

Redis 实现分布式Session 登录相关细节

Redis 实现分布式Session 登录 借助 Redis 对 Session 信息进行统一的存储和管理&#xff0c;这样无论请求发送到哪台服务器&#xff0c;服务器都会去同一个 Redis 获取相关的 Session 信息&#xff0c;这样就解决了分布式系统下 Session 存储的问题。 【发送短信】校验手机号…