Linux 下信号的保存和处理

devtools/2025/1/12 10:31:13/

信号的几个状态

  1. 信号抵达: 当接收到的信号被处理时, 此时就成为信号的抵达
  2. 信号的未决: 从信号的产生到信号抵达这个时间段之间, 称为信号未决
  3. 信号阻塞: 当进程设置了某个信号为阻塞后, 这个进程就不会在接收到这个信号
  4. 信号忽略: 将信号设置为忽略后, 接收到这个信号, 对这个信号的处理就是忽略

阻塞和忽略:

阻塞是进程没有收到对应的信号, 所以没有任何处理.

忽略接收到了信号, 但是对这个信号的处理就是不做任何处理, 进行忽视

虽然两者的行为是一样的, 没有任何处理, 但是本质还是有差别的

信号的保存

进程要对对接收到的信号处理, 那么就需要存在一块空间来存储接收到的信号.

在进程 PCB 中会存在三张表

1. block 表

block 表实际上是一个位图, 每一个比特位都对应一个信号.

信号对应比特位上要么是0, 要么是1.

1则代表在这个进程中, 这个比特位对应的信号设置为阻塞. 进程不接受此信号.

所以这张表也称为信号屏蔽字

2. pending 表

pending 表也是一个位图, 用来记录进程是否接收到了比特位对应的信号.

比特位为0表示没有接收到了对应位的信号. 为1表示接收到对应的信号.

这张表也可以称为未决表, 因为其中记录的信号都还未处理.

3. handler 表

handler 表和前两个表不同, handler 表是一个数组. 准确来说是一个函数指针数组.

这个表中记录着对应信号的处理函数地址. 当接收到信号时就会去调用对应的处理函数.

在上面的信号状态中, 有一个信号忽略, 实际上就是将 handler 表中的对应信号的函数指针设置为"SIG_IGN". SIG_IGN 是一个宏, 本质还是一个函数指针.

信号的一些操作

上面讲了信号存在阻塞状态, 还存在忽略状态. 除了系统默认的初始配置, 我们也可以手动进行设置.

1. 阻塞信号的设置

上面了解到阻塞表 (block) 是一个位图. 所以需要先来了解一下位图的使用.

sigset_t 类型就是位图

int sigemptyset(sigset_t *set) // 将每一个比特位都设置为 0

int sigfillset(sigset_t *set); // 将每一个比特位都设置为 1

int sigaddset(sigset_t *set, int signum); // 将第 signum 比特位设置为 1

int sigdelset(sigset_t *set, int signum); // 将第 signum 比特位设置为 0

int sigismember(const sigset_t *set, int signum); // 判断第 signum 比特位是0还是1并返回

当设置好了位图后, 使用函数 sigprocmask 来设置阻塞表

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

  • how:指定如何修改信号阻塞集,可以取以下值:
    • SIG_BLOCK:将 set 中的信号添加到当前信号阻塞集中。
    • SIG_UNBLOCK:将 set 中的信号从当前信号阻塞集中删除。
    • SIG_SETMASK:将当前信号阻塞集设置为 set
  • set:指向 sigset_t 类型的指针,表示要修改的信号集。
  • oldset:指向 sigset_t 类型的指针,用于存储修改前的信号阻塞集。如果不需要,可以传 NULL

返回值:

  • 成功时返回 0。
  • 失败时返回 -1.
int main()
{sigset_t myset;sigemptyset(&myset);sigaddset(&myset, 1);sigprocmask(SIG_BLOCK, &myset, NULL);// 将本进程的一号信号设置为阻塞return 0;
}

2. 信号处理函数设置

接下来我们来设置对于信号的处理函数.

我们需要使用 signal 函数.

signum: 要设置几号信号的处理函数, 可以使用数字, 也可以使用信号名如: SIGINT

  • SIG_DFL:恢复信号的默认处理行为。
  • SIG_IGN:忽略信号。
  • 自定义处理函数:用户定义的处理函数指针。

handler: 接收到信号时, 要调用的处理函数

void func(int signum) // 参数不能省略
{cout << "接收到信号: " << signum << endl;
}int main()
{signal(1, func);// 当进程接收到 1 号信号时, 就会调用函数 func, 进程就会打印信息return 0;
}

信号的处理时机

从内核态返回用户态时, 会进行信号的处理

内核态和用户态都是操作系统的一种运行状态.

用户态拥有的权限较低, 只能访问自己的地址空间, 不能直接访问内核空间.

内核态拥有最高的权限, 可以访问系统的任何资源, 执行所有操作.

区分用户态和内核态是对操作系统的一种保护方式, 可以防止用户程序对系统资源的非法访问. 保护系统的稳定和安全.

那么什么时候会发生用户态和内核态之间的转换

系统调用, 如: 使用 read, write 函数, 这些就是系统提供的接口, 当调用这些系统调用时, 就会发生用户态到内核态的转换, 当执行完系统调用后, 就会从内核态转换为用户态.

此时, 就会对进程接收到的信号处理.


http://www.ppmy.cn/devtools/149848.html

相关文章

K-Means 聚类算法:用生活场景讲解机器学习的“分组”方法

一、K-Means 算法概述 K-Means 是一种经典的无监督学习聚类算法&#xff0c;目的是将数据集中 n 个样本划分成 K 个簇&#xff08;cluster&#xff09;&#xff0c;每个样本根据其特征被归入与之最接近的簇。简单来说&#xff0c;这就像在超市购物时&#xff0c;顾客会被根据购…

【C++开源库】Boost.Asio网络库使用介绍

Boost.Asio是一个功能强大的C网络库&#xff0c;它提供了对网络编程的高级抽象&#xff0c;使得在C中进行网络通信变得更加容易和高效。Asio是Boost库的一部分&#xff0c;它支持多种操作系统&#xff0c;包括Windows、Linux和macOS等。 特点与优势 异步编程模型&#xff1a;B…

word论文排版常见问题汇总

word论文排版常见问题汇总 常用快捷键&#xff1a; Alt F9 正常模式与域代码模式切换 Ctrl F9 插入域代码 F9 刷新域代码显示&#xff0c;要注意选定后刷新才会有效果 word中在当前列表的基础上修改列表 在使用word时&#xff0c;我们会定义一个列表&#xff0c;并将其链接…

关于扫描模型 拓扑 和 传递贴图工作流笔记

关于MAYA拓扑和传递贴图的操作笔记 一、拓扑低模: 1、拓扑工作区位置: 1、准备出 目标 高模。 (高模的状态如上 ↑ )。 2、打开顶点吸附,和建模工具区,选择四边形绘制. 2、拓扑快捷键使…

【网络安全 | 漏洞挖掘】通过监控调试模式实现价值$15k的RCE

未经许可,不得转载。 前言 你是否曾遇到过这样一种情况:明明发现了一个可疑的端点,直觉告诉你它可能存在漏洞,但却无法确定其背后的逻辑,更不用说利用它了?在这篇文章中,我将分享一种技术,它让我的黑盒测试变得如同半白盒测试。这种方法帮助我发现了多个漏洞,并最终实…

设计模式 行为型 责任链模式(Chain of Responsibility Pattern)与 常见技术框架应用 解析

责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为型设计模式&#xff0c;它允许将请求沿着处理者链进行发送。每个处理者对象都有机会处理该请求&#xff0c;直到某个处理者决定处理该请求为止。这种模式的主要目的是避免请求的发送者和接收者之间…

Network Compression(李宏毅)机器学习 2023 Spring HW13 (Boss Baseline)

1. Introduction to Network Compression 深度学习中的网络压缩是指在保持神经网络性能的同时,减少其规模的过程。这非常重要,因为深度学习模型,尤其是用于自然语言处理或计算机视觉的大型模型,训练和部署的计算成本可能非常高。网络压缩通过降低内存占用并加快推理速度,…

采用GPT生成的Python 的 2048 游戏

采用GPT生成的Python 的 2048 游戏 文章说明核心代码效果展示源码下载 文章说明 采用GPT生成的一个小工具&#xff0c;作为一个python开发小游戏的demo&#xff0c;打发时间的小代码&#xff0c;后续可以考虑继续利用GPT生成更多有趣的小游戏 核心代码 2048小游戏-1.0版本 impo…