【Linux】进程信号

【Linux】进程信号

在 Linux 编程世界中,信号(Signal)机制是一种极为关键的异步通信方式。它不仅是进程间通信的基础之一,也是操作系统与进程互动的重要通道。本文将从生活中的类比引入,再逐步深入技术细节,帮助读者系统性地掌握信号的概念、产生、处理、阻塞机制及相关编程实践。


一、信号是什么?

1.1 从生活场景谈起

你网购了几件商品,快递员在楼下时通知你取件,但你可能正忙着打游戏,五分钟后才下去。这段"知道快递来了但还没取"的时间,就像进程接收到信号但尚未处理的"未决状态"。

取快递的方式也多样:

  • 默认处理:自己打开快递使用;
  • 自定义处理:送人;
  • 忽略处理:扔床头不理。

这种过程是异步的,快递(信号)何时到来无法预知,只能在收到通知后"在合适的时机"处理。

1.2 从技术场景看信号

举例说明,当我们在 Shell 中执行一个前台程序时按下 Ctrl+C:

  • 键盘产生一个中断;
  • 操作系统捕捉中断并发送 SIGINT 信号;
  • 前台进程收到信号并终止。

二、信号基础知识

2.1 信号的定义

信号是进程间用于事件通知的一种机制,本质上属于"软中断",用于通知目标进程发生了某个事件。

2.2 信号种类与查看方式

使用命令 kill -l 可以查看系统支持的所有信号。信号通常由宏定义标识(如 SIGINT 是信号编号 2),可在 signal.h 中查到。


三、信号的产生方式

3.1 终端按键产生

如:

  • Ctrl+C → SIGINT,默认终止进程;
  • Ctrl+\ → SIGQUIT,默认终止并生成 core dump。

3.2 调用系统函数发送

常用函数:

  • kill(pid, signo):向指定进程发送信号;
  • raise(signo):向当前进程自身发送信号;
  • abort():强制终止自身进程;
  • alarm(seconds):定时发出 SIGALRM。

3.3 软件条件触发

如:

  • 写入已关闭的管道 → SIGPIPE;
  • 调用 alarm() → 在指定秒数后触发 SIGALRM。

3.4 硬件异常触发

如:

  • 除零 → SIGFPE;
  • 访问非法地址 → SIGSEGV。

四、信号的处理方式

信号的处理动作有三种:

  1. 忽略;
  2. 执行默认动作;
  3. 自定义处理函数(捕捉)。

示例代码:

c 复制代码
signal(SIGINT, handler); // 捕捉SIGINT

4.1 Core Dump 简介

当进程异常终止时,将内存内容保存为文件 core,可用于调试分析。需使用 ulimit -c 命令允许生成 core 文件。


五、信号的捕捉机制

5.1 内核中的捕捉流程

信号捕捉的本质是注册一个回调函数,在信号递达时中断当前流程并调用该函数。处理完信号后,再恢复原有上下文继续执行。

5.2 使用 sigaction

sigaction 提供更安全和灵活的信号处理方式,支持设置额外屏蔽信号、恢复上下文等操作。

示例用法:

c 复制代码
struct sigaction act;
act.sa_handler = handler;
sigaction(SIGINT, &act, NULL);

六、信号的阻塞与未决

6.1 概念区分

  • 阻塞(Block):信号被暂时挂起,不立即处理;
  • 未决(Pending):信号已产生,但因被阻塞暂未递达;
  • 递达(Delivery):信号处理动作被实际执行。

6.2 内核实现方式

信号在 PCB 中用两个标志位表示:

  • 是否阻塞;
  • 是否未决。

如果信号被阻塞,系统仅设置其未决标志;待解阻塞后再处理。


七、信号集与相关函数

信号集类型 sigset_t 用于描述多个信号状态。

常用函数包括:

c 复制代码
sigemptyset(&set);   // 初始化为空
sigfillset(&set);    // 所有信号
sigaddset(&set, sig);
sigdelset(&set, sig);
sigismember(&set, sig); // 是否包含某信号

7.1 操作信号屏蔽字:sigprocmask

用于读取/更改当前进程的阻塞信号集。

c 复制代码
sigprocmask(SIG_BLOCK, &set, NULL);

7.2 查询未决信号:sigpending

c 复制代码
sigpending(&pending_set);

八、可重入函数与信号安全

在信号处理函数中使用的代码必须是可重入 的。不可重入函数(如 malloc, printf)在信号处理时会引发数据错乱。


九、关键字 volatile 的作用

当变量被 volatile 修饰时,编译器不会优化其访问操作,确保对该变量的访问都在真实内存中进行,防止因缓存导致的判断失效。

c 复制代码
volatile int flag = 0;

避免如下问题:

c 复制代码
while (!flag); // 如果没有volatile修饰,可能永远不退出循环

十、SIGCHLD 信号与子进程管理

SIGCHLD 信号在子进程终止时发送给父进程。

10.1 信号处理函数方式

使用 signal(SIGCHLD, handler) 捕捉信号,在处理函数中调用 waitpid 回收子进程资源,避免僵尸进程。

10.2 SIG_IGN 简化处理

将 SIGCHLD 的处理动作设为 SIG_IGN 可自动回收子进程(Linux 专属行为)。


结语:

信号机制的设计体现了操作系统对异步事件控制的精巧思路。通过信号,进程得以与系统高效交互,也为开发者提供了强大的编程工具。

相关推荐
叼烟扛炮19 分钟前
[LangChain] 学习笔记(02):LCEL 链式调用与动态模型配置实战
服务器·开发语言·网络·笔记·学习·langchain
福建佰胜张工37 分钟前
深度解析 Allen-Bradley 150-B135NBDA 智能电机控制器:选型、参数与工业应用
运维·数据库·单片机·嵌入式硬件·安全·自动化
wefg143 分钟前
【Docker】镜像相关指令
运维·docker·容器
智慧光迅AINOPOL1 小时前
POF光电复合缆多业务承载原理
网络·安全·智能路由器
feng_you_ying_li1 小时前
linux之网络层
linux·运维·网络
步行cgn1 小时前
HTTP 请求报文结构详解:请求行、请求头、请求体各自的作用
网络·网络协议·http
未来之窗软件服务1 小时前
Linux 运维日志删除的多种方式—东方仙盟
linux·运维·服务器·仙盟创梦ide·东方仙盟
卓豪终端管理1 小时前
IT 运维视角下的终端数据安全:能力框架与落地清单
运维
小雉系统1 小时前
BcoreOS实战:用一个升级包,让Rocky Linux跑进Debian服务器
linux·运维·服务器·debian
thethefighter1 小时前
快速预览Word、WPS秒开,支持空格弹窗
linux·word·wps·快速预览·空格弹窗·nhdeepview