操作系统|信号(Signal)

前面我们讲解了共享存储、消息传递、管道三类可传输大批量数据的进程通信方式,今天介绍一种极简、轻量的进程交互手段 ——信号(Signal)。信号不传递复杂业务数据,仅用于告知进程 “某一特定事件已经发生”,是系统异常、中断、进程管控最常用的底层机制。

一、信号的核心作用

  1. 实现极简型进程间通信,核心能力只做事件通知,仅传递事件标记,无法携带大量传输数据;
  2. 作为程序异常、系统中断的配套处理机制,比如程序崩溃、强制终止、暂停运行等场景,全靠信号驱动处理逻辑。

二、信号的三大发送来源

信号一共有三类发送主体,工程中最常用kill函数完成发送操作,调用时需要指定接收进程的 pid、目标信号序号。

  1. 进程向另一个进程发送信号 例如终端手动执行 kill 命令杀死后台程序,本质就是当前 shell 进程给目标业务进程发送终止信号。
  2. 操作系统内核向进程发送信号 硬件异常、内存越界、除零错误、定时器超时等场景,由内核主动推送信号通知进程。
  3. 进程向自身发送信号 进程内部逻辑触发自检、主动终止、自我暂停时,可以调用接口给自己投递信号。

三、信号在系统中的保存方式

操作系统会在每个进程的 PCB(进程控制块) 内部,分配两组 N bit 长度的位向量:

  1. 待处理信号位向量:每一个比特位对应一类信号,比特置 1 代表该信号已经收到、等待被处理;
  2. 被阻塞信号位向量:标记哪些信号暂时需要屏蔽,即便收到也暂时不执行处理逻辑。 位向量是信号轻量化存储的核心,占用内存极小,匹配信号 “只做通知” 的定位。

     3.图解

(1)信号类型:8种--8个bit                

(2)待处理信号:表示其它进程发送过来的信号:图中发送过来信号类型1和类型8待处理

          被阻塞信号:表示不会使用的信号:图中信号7,8被屏蔽

                                                 

(3)发送信号:  kill(2666,1)表示发送信号类型1给pid为2666的进程。当两个进程发送相同类型的信号时,后到达是信号将被丢弃,图中OS的信号将被丢弃

四、信号的处理规则

1. 固定处理时机

进程只有在从内核态切换回用户态的瞬间,操作系统会例行扫描待处理信号队列;如果检测到存在未处理信号,立刻暂停原有业务逻辑,优先执行信号处理流程。 进程正在用户态全速运行、或是深陷内核态阻塞等待时,不会中途打断去响应信号。

处理时机图解:将block按位取反的11111100与pending按位与得10000000,类型1的比特位为一,表示处理信号1,其它为0表示不处理

2. 两种处理执行方案

方案 1:执行操作系统默认处理程序

内核为每一类信号都预设了标准处理逻辑,常见默认行为分为三类:

  1. 直接终止当前进程;
  2. 暂停进程运行;
  3. 直接忽略该信号,不做任何操作(例:Linux 系统 SIGWINCH 窗口大小变更信号)。
方案 2:执行用户自定义信号处理程序

进程可以通过系统调用,手动注册自定义的信号回调函数;自定义逻辑会完全覆盖操作系统默认处理行为,收到信号后优先运行开发者编写的处理代码。

用户可以自定义信号的处理内容,没有定义是则会使用系统提供的默认处理方式

3. 信号处理后的配套运行细节

  1. 信号处理程序运行结束后,正常情况下会回到进程被打断的位置,执行下一条原有指令;只有当处理程序内部主动终止、阻塞进程时,才不会恢复原有流程。
  2. 某一类信号完成处理后,PCB 里对应待处理(pending)比特位会被重置为 0,标记该信号已办结。
  3. 重复同型号信号会直接丢弃:位向量只用 1 个比特记录一类信号 “有无状态”,不统计接收次数。短时间连续发来多条一模一样的信号,系统仅保留一次记录,多余重复信号直接丢失。
  4. 多类信号同时抵达的优先级:如果同一时刻检测到多种不同的待处理信号,操作系统通常优先处理信号序号数值更小的信号。

五、信号的五大关键特性

  1. 信号标准不统一:Windows、Linux、macOS 等不同操作系统,定义的信号编号、信号含义存在差异,跨平台程序需要做兼容适配;
  2. 同类重复信号会直接丢弃:位向量只用 1 个比特记录一类信号 “有无”,不统计接收次数。短时间连续收到多条相同信号,只会保留一次记录,多余重复信号直接丢失;
  3. 存在不可管控的特权信号:部分高危系统信号,既不允许用户自定义处理函数,也无法被代码阻塞屏蔽;典型例子为 Linux 中的 SIGKILL(强制杀死进程)、SIGSTOP(强制暂停进程);
  4. 通信负载极低:全程只有标记位传递,无内存拷贝、大数据传输开销;
  5. 属于异步通知:信号到来时机完全不可预测,随时可能打断进程正常业务流程。

六   问题

1.各个进程的自定义处理信号相互独立

如图,假设进程1信号2自定义了处理程序,而进程2没有自定义,则进程2的信号不会受到进程1的影响,即运行时进程1的信号2唤醒自定义处理程序,进程2的信号2唤醒系统默认处理程序

2.信号与异常

信号是操作系统异常处理的配套补充机制,进程运行中产生异常时,内核捕获后分为两种处理路径:

  1. 内核可独立完整处理的异常 例如缺页异常,操作系统内核自身就能完成页面置换、内存调度等全部修复工作,全程无需通知用户进程,不会发送任何信号。
  2. 内核无法独立处理、需要用户进程配合的异常 部分异常内核仅能识别故障,无法自主修复,此时内核依靠信号机制向出错进程发送专属异常信号,交由进程选择处理方式。 以 Linux 除以 0 异常举例:
  3. 运算出错触发硬件异常,操作系统内核第一时间捕获异常事件;
  4. 内核主动向发生错误的进程发送 SIGFPE 算术异常信号;
  5. 两种处理分支: (1)默认处理:系统内置 SIGFPE 处理程序,直接终止进程并导出内存崩溃转储文件; (2)自定义处理:进程提前注册自定义 SIGFPE 回调函数,覆盖默认行为,可实现打印错误日志、重试计算、优雅退出等个性化容错逻辑。
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐