【Linux】信号集及相关函数(sigemptyset、sigfillset、sigprocmask)

news/2024/11/8 2:48:12/

目录

  • 1、信号集
  • 2、自定义信号集相关函数
  • 3、sigprocmask函数
      • 函数解析
      • 代码举例

橙色

1、信号集

  • 多个信号组成的一个集合称为信号集,其系统数据类型为 sigset_t 。

  • 在 PCB 中有两个非常重要的信号集,一个称为“阻塞信号集”,另一个是“未决信号集”。信号产生但是没有被处理 (未决),在内核中将所有的没有被处理的信号存储在一个集合中 (未决信号集)。这个未决状态的信号,需要被处理,处理之前需要和另一个信号集(阻塞信号集),进行比较,在处理的时候和阻塞信号集中的标志位进行查询,看是不是对该信号设置阻塞了。

  • 信号的“未决”是一种状态,指的是从信号的产生到信号被处理前的这一段时间。

  • 信号的“阻塞”是一个开关动作,指的是阻止信号被处理,但不是阻止信号产生。

  • 信号的阻塞就是让系统暂时保留信号留待以后发送。由于另外有办法让系统忽略信号.所以一般情况下信号的阻塞只是暂时的,只是为了防止信号打断敏感的操作。

2、自定义信号集相关函数

以下信号集相关的函数都是对自定义的信号集进行操作

/*int sigemptyset(sigset_t *set);- 功能:清空信号集中的数据,将信号集中的所有的标志位置为0- 参数:set,传出参数,需要操作的信号集- 返回值:成功返回0, 失败返回-1int sigfillset(sigset_t *set);- 功能:将信号集中的所有的标志位置为1- 参数:set,传出参数,需要操作的信号集- 返回值:成功返回0, 失败返回-1int sigaddset(sigset_t *set, int signum);- 功能:设置信号集中的某一个信号对应的标志位为1,表示阻塞这个信号- 参数:- set:传出参数,需要操作的信号集- signum:需要设置阻塞的那个信号- 返回值:成功返回0, 失败返回-1int sigdelset(sigset_t *set, int signum);- 功能:设置信号集中的某一个信号对应的标志位为0,表示不阻塞这个信号- 参数:- set:传出参数,需要操作的信号集- signum:需要设置不阻塞的那个信号- 返回值:成功返回0, 失败返回-1int sigismember(const sigset_t *set, int signum);- 功能:判断某个信号是否阻塞- 参数:- set:需要操作的信号集- signum:需要判断的那个信号- 返回值:1 : signum被阻塞0 : signum不阻塞-1 : 失败*/

代码举例

#include <signal.h>
#include <stdio.h>int main() {// 创建一个信号集,一开始可能有某些标志位为1,所以下一步需要清空sigset_t set;// 清空信号集的内容sigemptyset(&set);// 判断 SIGINT 是否在信号集 set 里int ret = sigismember(&set, SIGINT);if(ret == 0) {printf("SIGINT 不阻塞\n");} else if(ret == 1) {printf("SIGINT 阻塞\n");}// 添加几个信号到信号集中sigaddset(&set, SIGINT);sigaddset(&set, SIGQUIT);// 判断SIGINT是否在信号集中ret = sigismember(&set, SIGINT);if(ret == 0) {printf("SIGINT 不阻塞\n");} else if(ret == 1) {printf("SIGINT 阻塞\n");}// 判断SIGQUIT是否在信号集中ret = sigismember(&set, SIGQUIT);if(ret == 0) {printf("SIGQUIT 不阻塞\n");} else if(ret == 1) {printf("SIGQUIT 阻塞\n");}// 从信号集中删除一个信号sigdelset(&set, SIGQUIT);// 判断SIGQUIT是否在信号集中ret = sigismember(&set, SIGQUIT);if(ret == 0) {printf("SIGQUIT 不阻塞\n");} else if(ret == 1) {printf("SIGQUIT 阻塞\n");}return 0;
}

在这里插入图片描述

3、sigprocmask函数

函数解析

/*int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);- 功能:将自定义信号集中的数据设置到内核中(设置阻塞,解除阻塞,替换)- 参数:- how : 如何对内核阻塞信号集进行处理SIG_BLOCK: 将用户设置的阻塞信号集添加到内核中,内核中原来的数据不变假设内核中默认的阻塞信号集是mask, mask | setSIG_UNBLOCK: 根据用户设置的数据,对内核中的数据进行解除阻塞mask &= ~set(也就是先对set取反,再与mask按位与),假设内核中默认的阻塞信号集是maskSIG_SETMASK:覆盖内核中原来的值- set :已经初始化好的用户自定义的信号集- oldset : 保存设置之前的内核中的阻塞信号集的状态,可以是 NULL- 返回值:成功:0失败:-1设置错误号:EFAULT、EINVALint sigpending(sigset_t *set);- 功能:获取内核中的未决信号集- 参数:set,传出参数,保存的是内核中的未决信号集中的信息。
*/

代码举例

该代码首先自定义了信号集 set,并把 SIGINT 和 SIGQUIT 信号放入其中。然后又通过 sigprocmask 函数修改了内核中的阻塞信号集。接着设置了死循环,在循环内创建了一个信号集pendingset,并将当前的未决信号集的数据放入pendingset,接着遍历该信号集的前31位。

当你运行该程序时,首先输出的都会是0,接着在循环10次之前,按ctrl+c,打印出的第二位就会从0变成1(其实也就是你按ctrl+c的时候,就代表向系统发送 SIGINT 信号,但该信号通过上面的操作在内核中的阻塞信号集中已经被设置为1了,所以当系统接收到该信号时,也就会阻塞,因此该信号状态为未决,打印出的未决信号集的第二位(代表SIGINT)也就变为了1)。

10次循环之后,解除了阻塞。之前按ctrl+c也没办法停止死循环,但按完ctrl+c且10次循环之后,死循环就会自动停止,因为程序设置10次之后解除我们之前设置的信号阻塞,此时系统不再阻塞之前所发送的SIGINT 信号,于是SIGINT 信号发挥自己的作用,停止了该进程。

// 编写一个程序,把所有的常规信号(1-31)的未决状态打印到屏幕
// 设置某些信号是阻塞的,通过键盘产生这些信号#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>int main() {// 设置2、3号信号阻塞sigset_t set;sigemptyset(&set);// 将2号和3号信号添加到信号集中sigaddset(&set, SIGINT);sigaddset(&set, SIGQUIT);// 修改内核中的阻塞信号集sigprocmask(SIG_BLOCK, &set, NULL);int num = 0;while(1) {num++;// 获取当前的未决信号集的数据sigset_t pendingset;sigemptyset(&pendingset);sigpending(&pendingset);// 遍历前32位for(int i = 1; i <= 31; i++) {if(sigismember(&pendingset, i) == 1) {printf("1");}else if(sigismember(&pendingset, i) == 0) {printf("0");}else {perror("sigismember");exit(0);}}printf("\n");sleep(1);if(num == 10) {// 解除阻塞sigprocmask(SIG_UNBLOCK, &set, NULL);}}return 0;
} 

在这里插入图片描述


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

相关文章

FreeRTOS移植

准备工作 准备基础工程 基础工程越简单越好&#xff0c;这里直接用之前的跑马灯工程作为基础工程。 FreeRTOS源码 FreeRTOS源码就是Source文件 FreeRTOS移植 向工程中添加相关文件 添加FreeRTOS源码 在基础工程下创建一个文件夹放FreeRTOS源码&#xff0c;portable文件…

关于FLAME和SMPL模型

英文参考文献&#xff1a;https://medium.com/offnote-labs/3d-face-and-body-reconstruction-95f59ada1040 一个训练好的FLAME模型的输入是一个参数向量&#xff0c;包括形状参数、姿势参数和表情参数。这些参数分别控制人脸的身份特征、头部的旋转和平移、面部的表情变化。一…

Python可视化工具分享

今天和大家分享几个实用的纯python构建可视化界面服务&#xff0c;比如日常写了脚本但是不希望给别人代码&#xff0c;可以利用这些包快速构建好看的界面作为服务提供他人使用。有关于库的最新更新时间和当前star数量。 1、 streamlit (23.3k Updated 2 hours ago) Streamlit…

数据全生命周期管理

数据存储 时代"海纳百川&#xff0c;有容乃大"意味结构化、半结构和非结构化多样化的海量的 &#xff0c;也意味着批数据和流数据多种数据形式的存储和计算。面对不同数据结构、数据形式、时效性与性能要求和存储与计算成本等因素考虑&#xff0c;应该使用适合的存储…

metaRTC+ZLMediaKit实现webrtc的推拉流

概述 ZLMediaKit是一个基于C11的高性能运营级流媒体服务框架&#xff0c;是一个支持webrtc SFU的优秀的流媒体服务器系统。 metaRTC新版本支持whip/whep协议&#xff0c;支持whip/whep协议的ZLMediaKit推拉流。 信令通信 ZLMediaKit新版本支持whip和whep协议&#xff0c;支…

【网络工程师人手必备的常用网络命令合集,整理收藏!】

在计算机网络中经常要对网络进行管理&#xff0c;测试&#xff0c;这时就要用到网络命令。今天就为大家整理了一些网络工程师必备的一些常用网络命令合集&#xff0c;建议收藏后观看哦&#xff01; ping命令 ping是个使用频率极高的实用程序&#xff0c;主要用于确定网络的连…

一图看懂!RK3568与RK3399怎么选?

▎简介 RK3568和RK3399都是Rockchip公司的处理器&#xff0c;具有不同的特点和适用场景。以下是它们的主要区别和应用场景。 ▎RK3568 RK3568是新一代的高性能处理器&#xff0c;采用了22nm工艺&#xff0c;具有更高的性能和更低的功耗。它支持4K视频解码和编码&#xff0c;支持…

计算机分类——软考小知识

目录 一、按照计算机体积和工作能力划分 二、按照指令系统划分 一、按照计算机体积和工作能力划分 个人移动设备:带有多媒体用户界面的无线设备&#xff0c;如智能手机、平板电脑等 桌面计算机: 基于超大规模集成电路技术的CPU&#xff0c;包括低端的上网本、笔记本、台式机…