Linux 信号

信号是进程之间事件异步通知的一种方式,属于软中断

在上面这句话中,解释了信号这个词,但是又引入了两个新的概念:异步软中断

异步

异步 比较容易解释,我们日常生活中经常使用到同步这个词,而异步,正是和其相反的概念。不同人在同一时间做相同的事,即为同步 。那么不同人在同一时间做不同的事,即为异步。对于计算机,我们只需要把 "人" 换成 "进程" ,就可以解释计算机中的异步是何种意思了。

那么什么是软中断呢?这个涉及到的内容在我们学习完信号之后再讲解会比较容易理解,现阶段,我们先这样理解: "信号" 可以让进程 "中断" 当前行为,去执行其他行为。

信号产生

产生信号的东西叫做信号源,它可以是硬件,比如:键盘,鼠标等;也可以是软件,比如:系统调用函数等。

我们或已经知道,按下键盘的 ctrl+C ,可以终止一个进程,这就是硬件作为信号源的例子。这时我们引入一个问题:操作系统是怎么知道键盘有数据的?这个问题,我们留到讲中断时再讲解。还有硬件异常也会产生信号,如:除0,野指针。

我们也可以使用系统调用函数来向进程发送一个信号,最典型的就是kill 了,它可以向指定的一个进程发送指定的信号(自己给别人发),比如 kill -9 可以杀死进程。

raise ,给当前进程发指定的信号(自己给自己发)。

abort,使当前进程接收到信号而异常终止,并且会让进程产生核心转储(core dump),方便调试。

有哪些信号

信号有很多,我们可以在 Linux 中使用 kill -l 查看:

其中 1-31 号信号为标准信号 ,34-64号信号为实时信号

对于上图,有三个点需要解释:

1.为什么没有 32,33 号?这两个信号被 NPTL 线程库预留内核自用,用户不能使用。

2.标准信号中的 9,19 号信号无法被捕捉。

3.kill 只能发送标准信号。

信号保存

对于信号保存,我们先引入三个概念:递达未决阻塞

递达:实际执行信号的处理动作,有三种情况:自定义,默认,忽略。

未决:信号从产生到递达之间的状态。

阻塞:信号被保持在未决状态,即被阻塞。

进程的 task_struct 结构体中有三张表,它们相互配合完成对信号的保存与识别任务。

信号的号数 -1 就是对应数据结构的下标。block(阻塞信号屏蔽字) 表示信号是否被阻塞,pending(未决信号位图) 表示是否接收到该信号,handler(信号处理函数指针数组) 表是对该信号的处理方法。

block 和 pending 都是位图。

信号处理

前面说到递达时,说到信号处理的三种情况:自定义,默认,忽略。我们从简单到复杂来谈谈:

默认 (SIG_DFL):默认就是内核预设的行为,比如 2 号信号是默认杀死进程。

忽略 (SIG_IGN):进程接收到信号后直接丢弃,完全无响应。

自定义:使用函数捕获信号,暂停主程序,跳转到你自己定义的 handler 执行相应任务。

进程处理信号的流程简单来说就是:进程接收到信号,对应 pending 表的位置由 0 变 1,如果 block 对应位置为0,则可以执行 handler 对应位置的函数,否则等待。

对于自定义捕获信号,有两个函数:

signal

sigaction

signal 的第一个参数是具体信号的宏,第二个参数是你自定义的函数。它简单,易用,但不稳定。

sigaction 就比较可靠了,第一个函数依然是具体信号的宏,但是第二个和第三个参数都是一个结构体指针,这是什么呢?

首先我们得知道那个结构体是什么:

这是一个用来存放 "信号处理方案" 的容器,其实进程对信号捕获再处理,都是通过这个容器来实现的,所以 signal 本质是对 sigaction 的简易封装。

对于 sigaction 我们创建一个 struct sigaction 对象,修改里面的成员来对信号做出处理,两个结构体指针参数,一个指向新修改出的结构体,另一个指向旧的结构体,"备份" 原来的处理方式。

相关推荐
天平1 小时前
油猴脚本创建webworker踩坑记录
前端·javascript·typescript
原则猫3 小时前
前端基础大厦
前端
陈随易4 小时前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·后端·程序员
SoaringHeart5 小时前
Flutter进阶:基于 EasyRefresh 的下拉刷新封装 n_easy_refresh_mixin.dart
前端·flutter
IT_陈寒6 小时前
Vite的热更新突然不香了,排查三小时差点砸键盘
前端·人工智能·后端
子兮曰7 小时前
Agency-Agents 深度解析:400+ AI 专家的"梦之队"如何重塑开发工作流
前端·后端·vibecoding
竹林8188 小时前
用 The Graph 查询链上数据实战:从手搓 RPC 到 Subgraph,我的 NFT 项目数据加载快了 10 倍
前端·javascript
妙码生花8 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十九):点选验证码代码逐行目检
前端·后端·go
Awu12279 小时前
⚡从零开发 Agent CLI(五)实现一个可治理、可扩展的工具系统
前端·人工智能·claude
咪库咪库咪9 小时前
Vue3-生命周期
前端