Linux:进程通信(二)信号的保存

news2025/1/13 6:15:00

目录

一、信号的处理是否是立即处理的?

 二、信号如何保存

1、阻塞、未决、递达

2、信号集

3、信号集操作函数

4、sigprocmask函数

5、sigpending 函数


上篇文章我们讲解了信号的产生:Linux:进程信号(一)信号的产生

接下来我们来看一下信号的保存

一、信号的处理是否是立即处理的?

        信号的处理是否立即进行,取决于信号的类型、进程的当前状态,以及进程对信号的处理策略。

  1. 信号的优先级:某些信号需要立即处理,比如 SIGKILL(强制终止进程)和 SIGSTOP(暂停进程)。这些信号一旦被发送给目标进程,操作系统会立即采取行动。其他信号,比如 SIGTERMSIGUSR1,可能会被延迟处理,特别是在进程有更高优先级的任务在进行时。

  2. 进程的状态:如果进程正在内核态(如系统调用期间),信号的处理可能被延迟,直到进程回到用户态。此外,如果进程正在被其他信号阻塞,或处于某种临界区,信号也可能被暂时推迟。

  3. 信号的阻塞和掩码:进程可以通过信号掩码来阻止某些信号的立即处理。操作系统将这些阻塞的信号放入进程的信号队列中,直到进程解除阻塞。

  4. 信号处理函数:进程可以设置信号处理函数。当信号到达时,如果进程当前正在运行中,它可能会等到适当的时机(如下一个调度周期)才调用信号处理函数。

 二、信号如何保存

信号需要被进程记录下来,以确保即使在信号到达时进程无法立即处理时,信号也不会丢失。这种记录通常发生在进程的信号队列中。

信号队列是内核为每个进程维护的一个数据结构,用于存储已经到达但尚未被处理的信号。当进程接收到信号时,内核将信号放入进程的信号队列中,然后等待进程在适当的时机处理它们。这样做可以确保即使进程在信号到达时处于某种阻塞状态,也能够在稍后的时候处理这些信号。

信号队列通常存储在内核的内存中,并且对于每个进程都有一个单独的信号队列。进程可以使用系统调用来检查它的信号队列,并且可以对信号队列进行操作,比如阻塞或解除阻塞某些信号。

1、阻塞、未决、递达

实际执行信号的处理动作称为信号递达(Delivery)
信号从产生到递达之间的状态,称为信号未决(Pending)
进程可以选择阻塞 (Block ) 某个信号。
被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.
注意 , 阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

 如下图所示

比特位的位置表示信号的编号,比如图中是三号信号,三号信号产生后,未决信号集对应位置为1,内核来判断是否应该被处理,如果被处理则置为0 。而如果该信号被阻塞,那么就不会被处理,直到阻塞解除。

那么信号集如何管理呢:

2、信号集

sigset_t

sigset_t 用于表示一组信号,通常用于表示被阻塞的信号集合或者待处理的信号集合。

在内部实现上,sigset_t 可以被看作是一个位图,其中每个位代表一个信号。如果某个位被设置为 1,则表示对应的信号被包含在集合中;如果被设置为 0,则表示对应的信号不在集合中。

这种位图的表示方式非常高效,因为它可以用很小的内存空间表示很多信号。通常情况下,sigset_t 的大小被限制在一个字(通常是 32 位或 64 位)的大小范围内,所以它适用于表示系统支持的信号数量。

sigset_t可以本质上被视为一个位图 ,关于位图我们前面也介绍过:C++:Hash应用【位图与布隆过滤器】

3、信号集操作函数

sigset_t 类型对于每种信号用一个 bit 表示 有效 无效 状态 , 至于这个类型内部如何存储这些 bit 则依赖于系统实现, 从使用者的角度是不必关心的 , 使用者只能调用以下函数来操作 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(sigset_t *set): 此函数用于将信号集合 set 清空,即将所有信号从集合中移除,使得 set 表示一个空集。调用此函数后,set 中不包含任何信号。

  • sigfillset(sigset_t *set): 此函数用于将信号集合 set 填满,即将所有信号添加到集合中,使得 set 包含系统支持的所有信号。调用此函数后,set 中包含所有可能的信号。

  • sigaddset(sigset_t *set, int signo): 此函数用于向信号集合 set 中添加指定的信号 signo。添加成功后,set 中将包含 signo 代表的信号。

  • sigdelset(sigset_t *set, int signo): 此函数用于从信号集合 set 中删除指定的信号 signo。删除成功后,set 中将不再包含 signo 代表的信号。

  • sigismember(const sigset_t *set, int signo): 此函数用于检查指定的信号 signo 是否包含在信号集合 set 中。如果 signo 存在于 set 中,则返回非零值;否则返回 0。

需要注意的是在使用 sigset_ t 类型的变量之前 , 一定要调 用 sigemptyset sigfillset 做初始化 , 使信号集处于确定的状态。初始化sigset_t 变量之后就可以在调用 sigaddset sigdelset 在该信号集中添加或删除某种有效信号。

4、sigprocmask函数

调用函数 sigprocmask 可以读取或更改进程的信号屏蔽字 ( 阻塞信号集 )
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset); 
返回值:若成功则为0,若出错则为-1
如果调用 sigprocmask 解除了对当前若干个未决信号的阻塞 , 则在 sigprocmask 返回前 , 至少将其中一个信号递达。
通过man sigprocmask命令可以看到

how参数的取值:

我们通过代码来测试一下:

#include<signal.h>
#include<iostream>
#include <sys/types.h>
#include <unistd.h>


int main()
{
    sigset_t set,oset;
    sigemptyset(&set);
    sigemptyset(&oset);
    sigaddset(&set,SIGINT);//屏蔽2号信号
    sigprocmask(SIG_BLOCK,&set,&oset);
    while(true)
    {
        std::cout<<"我是"<<getpid()<<"号进程"<<std::endl;
        sleep(1);
    }
    return 0;
}

运行代码后我们使用Ctrl+c发出2号信号,没有停止

因为2号信号已经被屏蔽,就算使用kill命令发出也是一样的:

 

那么我们来解除阻塞后会不会恢复正常呢:

#include<signal.h>
#include<iostream>
#include <sys/types.h>
#include <unistd.h>


int main()
{
    sigset_t set,oset;
    sigemptyset(&set);
    sigemptyset(&oset);
    sigaddset(&set,SIGINT);//屏蔽2号信号
    sigprocmask(SIG_BLOCK,&set,&oset);
    while(true)
    {
        std::cout<<"我是"<<getpid()<<"号进程"<<std::endl;
        sleep(20);
        sigprocmask(SIG_UNBLOCK,&set,&oset);//20秒后解除阻塞
    }
    return 0;
}

可以看到

在未解除前,我们发送2号信号是没用的,但在20秒后,会自动处理2号信号退出。

因为阻塞并不是处理,信号依旧保持未决,暂时不递达,直到解除对信号的阻塞。

需要注意的是,9号信号是不会被屏蔽的,大家可以在上面代码的基础上测试。

5、sigpending 函数

sigpending 函数用于获取当前被阻塞但是仍然排队等待传递给进程的信号集合。也就是未决信号集

int sigpending(sigset_t *set);
调用成功则返回 0, 出错则返回 -1。
我们使用下列代码来测试:
#include<signal.h>
#include<iostream>
#include <sys/types.h>
#include <unistd.h>

void printsigset(sigset_t *set)
{
    for(int i=31;i>=0;i--)
    {
        if(sigismember(set,i))
        {
            std::cout<<"1";
        }
        else
        {
            std::cout<<"0";
        }
    }
    std::cout<<std::endl;
}
int main()
{
    sigset_t set,oset;
    sigemptyset(&set);
    sigemptyset(&oset);
    sigaddset(&set,SIGINT);//屏蔽2号信号
    sigprocmask(SIG_BLOCK,&set,&oset);
    while(true)
    {
        std::cout<<"我是"<<getpid()<<"号进程"<<std::endl;
        sigpending(&oset);
        printsigset(&oset);
        sleep(1);
    }
    return 0;
}

运行后可以看到:

当收到2号进程后,信号集对应的位置置为1,但是没有被执行,因为2号信号被阻塞了,按Ctrl-\仍然可以终止程序,因为SIGQUIT信号没有阻塞。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1654210.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C语言】字符函数和字符串函数--超详解

前言&#xff1a; 在编程的过程中&#xff0c;我们经常要处理字符和字符串&#xff0c;为了⽅便操作字符和字符串&#xff0c;C语⾔标准库中提供了 ⼀系列库函数&#xff0c;接下来我们就学习⼀下这些函数。 1. 字符分类函数 C语⾔中有⼀系列的函数是专⻔做字符分类的&#…

实战BACnet/IP标准通信网关在楼宇自动化中的应用

智慧楼宇建设实现不同设备间的互联互通是一项巨大挑战&#xff0c;尤其是在那些历史悠久的建筑中&#xff0c;新旧系统并存的情况尤为普遍。某大型商业综合体就面临着这样的困境&#xff1a;老旧的暖通空调系统采用Modbus RTU协议&#xff0c;而新部署的能源管理系统却要求BACn…

一文搞懂MySQL索引的数据结构

一、引言 在数据库管理系统中&#xff0c;索引是提高查询性能的关键所在。对于MySQL这类关系型数据库来说&#xff0c;索引更是其优化查询不可或缺的一部分。索引能够大大加快数据的检索速度&#xff0c;减少数据库的I/O操作&#xff0c;提高数据库的整体性能。本文将从索引的…

第2章.STM32开发C语言常用知识点

目录 0. 《STM32单片机自学教程》专栏总纲 2.1. STM32嵌入式开发C语言编程的不同 2.2. C语言常用知识点 2.2.1 位操作 2.2.2 define 宏定义 2.2.3 条件编译 2.2.3.1 #ifdef 2.2.3.2 #ifndef 2.2.3.3 #if !defined 2.2.4 extern 变量声明 2.2.5 typedef 类型别名 …

PPP点对点协议

概述 Point-to-Point Protocol&#xff0c;点到点协议&#xff0c;工作于数据链路层&#xff0c;在链路层上传输网络层协议前验证链路的对端&#xff0c;主要用于在全双工的同异步链路上进行点到点的数据传输。 PPP主要是用来通过拨号或专线方式在两个网络节点之间建立连接、…

Mysql:Before start of result set

解决方法&#xff1a;使用resultSet.getString&#xff08;&#xff09;之前一定要调用resultSet.next() ResultSet resultSet statement1.executeQuery();while (resultSet.next()){String username1 resultSet.getString("username");int id1 resultSet.getInt…

识货小程序逆向

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx a15018601872&#xff0c;x30184483x…

java io模型

目录 BIO 模型模型一&#xff1a;单线程服务器模型二&#xff1a;多线程服务器 NIO 模型模型一&#xff1a;遍历轮训 select/poll模型二&#xff1a;基于事件响应机制的 epoll BIO BIO 模型 模型一&#xff1a;单线程服务器 执行过程&#xff1a;阻塞等待 connection&#xff…

JS-拖拽元素放大缩小

效果左右布局&#xff0c;拖拽后&#xff0c;宽度放大缩小 其实自己写也可以&#xff0c;不过还是发现了两个好用的js库&#xff0c;既然不需要自己写&#xff0c;当然是能偷懒就偷懒 1、resizerjs 官网地址&#xff1a;https://github.com/eknowles/resizerjs <!doctype …

SPSS多元线性回归

&#xff08;要满足&#xff09;模型的假设条件需要对数据进行怎样处理&#xff1f;&#xff1f; 为了使数据满足多元线性回归的条件&#xff0c;通常需要进行以下预处理步骤&#xff1a; 1. 数据清洗&#xff1a;处理缺失值、异常值和重复值&#xff0c;确保数据质量。 2. 特…

Linux基础之git与调试工具gdb

目录 一、git的简单介绍和使用方法 1.1 git的介绍 1.2 git的使用方法 1.2.1 三板斧之git add 1.2.2 三板斧之git commit 1.2.3 三板斧之git push 二、gdb的介绍和一些基本使用方法 2.1 背景介绍 2.2 基本的使用方法 一、git的简单介绍和使用方法 1.1 git的介绍 Git是一…

NSSCTF中的web

目录 [第五空间 2021]WebFTP [LitCTF 2023]PHP是世界上最好的语言&#xff01;&#xff01; [SWPUCTF 2021 新生赛]PseudoProtocols [LitCTF 2023]导弹迷踪 [NISACTF 2022]easyssrf [第五空间 2021]WebFTP 1.进入页面&#xff0c;发现是登录页面&#xff0c;想到 弱口令&…

JAVA学习笔记(第三周)

文章目录 继承概述使用场景继承的特点子类继承的内容成员变量访问特点成员方法访问特点方法的重写构造方法this super 多态多态的表现形式多态的前提成员变量和方法调用instanceof优势弊端 包包名的规则全类名final常量 权限修饰符代码块 继承 概述 继承就是子类继承父类的特征…

【图书推荐】《从零开始大模型开发与微调:基于PyTorch与ChatGLM》

本书目的 本书详解大模型基本理论、算法、程序实现与应用实战&#xff0c;揭示ChatGLM大模型开发与微调技术&#xff0c;紧跟大模型技术发展趋势&#xff0c;利用ChatGLM大模型完成毕业论文和研究课题。 本书案例 基于PyTorch卷积层的MNIST分类实战PyTorch数据处理与模型展示…

Linux与windows网络管理

文章目录 一、TCP/IP1.1、TCP/IP概念TCP/IP是什么TCP/IP的作用TCP/IP的特点TCP/IP的工作原理 1.2、TCP/IP网络发展史1.3、OSI网络模型1.4、TCP/IP网络模型1.5、linux中配置网络网络配置文件位置DNS配置文件主机名配置文件常用网络查看命令 1.6、windows中配置网络CMD中网络常用…

初识C语言——第十一天

操作符&#xff1a; 1. 算数操作符&#xff1a; - * / % 2. 移位操作符&#xff1a; >> &#xff08;右移&#xff09; << &#xff08;左移&#xff09; 移动的是二进制位 例如&#xff1a; int ba<<1; 3. 位操作符&#xff1a; & 按位与 | 按位…

设置默认表空间和重命名

目录 设置默认表空间 创建的临时表空间 tspace4 修改为默认临时表空间 创建的永久性表空间 tspace3 修改为默认永久表空间 重命名表空间 将表空间 tspace3 修改为 tspace3_1 Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/13520…

Marin说PCB之国产电源芯片方案 ---STC2620Q

随着小米加入的造车大家庭&#xff0c;让这个本来就卷的要死的造车大家庭更加卷了。随之带来的蝴蝶效应就是江湖上各个造成门派都开始了降本方案的浪潮啊&#xff0c;开始打响价格战了。各家的新能源车企也是不得不开始启动了降本方案的计划了&#xff0c;为了应对降价的浪潮。…

程序员的实用神器——高效软件开发的秘诀

目录 前言 一、自动化测试工具 &#xff08;一&#xff09;常用的自动化测试工具 &#xff08;二&#xff09;编写有效的测试用例的建议 &#xff08;三&#xff09;提高代码覆盖率的方法 二、持续集成/持续部署 &#xff08;一&#xff09;持续集成&#xff08;CI&#…

QT实战百度语音识别

前言 随着学习的深入&#xff0c;感觉愈发缺乏满足感。刚好看到微信语音转文字的功能&#xff0c;经网上查询&#xff0c;发现可以使用 QT 百度语音识别技术 实现这一功能。当然&#xff0c;由于使用的 QT 和 百度语音识别&#xff0c;那么看不到一些具体的底层实现&#xff…