【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+CSIGINT,默认终止进程;
  • 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 专属行为)。


结语:

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

相关推荐
fulangxisikexi15 分钟前
ospf综合实验
网络
南极浮冰17 分钟前
【无标题】
linux·人工智能·python
小孙姐23 分钟前
Linux-Day02.Linux指令
linux·运维·服务器
@BreCaspian32 分钟前
Kazam产生.movie.mux后恢复视频为.mp4
linux·ubuntu·音视频
搞不懂语言的程序员1 小时前
Linux Epool的作用
linux·服务器
jzy37111 小时前
主机管理优化方案:安全加固、资源整合与跨团队协作
linux·tomcat
Neng_Miao1 小时前
文件与目录操作命令
linux·运维
_Kayo_1 小时前
VUE2 学习笔记17 路由
网络·笔记·学习
倔强的石头1061 小时前
【Linux指南】软件安装全解析:从源码到包管理器的进阶之路
linux·运维·服务器
爱地球的曲奇1 小时前
Linux环境下(Ubuntu)Fortran语言如何安装配置NetCDF
linux·ubuntu·netcdf