news 2026/5/5 7:23:27

深入解析Linux信号处理机制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深入解析Linux信号处理机制

一.信号

信号是一种用户,OS,其他进程,向目标进程发送异步事件的一种方式。

在详细的学习信号时我们先提出几个问题,带着问题去学习:

1.你怎么能识别信号呢?识别信号,是内置的。进程认识信号是程序员内置的特性。

2.信号产生之后,怎么处理的?如果没有产生,信号怎么处理?信号的处理方法,在信号产生之前就已经准备好了。

3.处理信号是立即处理吗?如果我在做优先级很高的事情可能并不是优先处理的。

4.怎么处理信号a.默认行为b.忽略信号c.自定义

- 实际执行信号的处理动作称为信号递达(Delivery)

- 信号从产生到递达之间的状态,称为信号未决(Pending)

- 进程可以选择阻塞(Block)某个信号(阻塞特定信号,信号产生了,一定把信号要进行pending,永远不递达,除非我们解除阻塞)

- 被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作

- 注意:阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作

二.所需要学习的函数

1.sgnal

signal是一个用于信号处理的库函数,主要作用是为特定的信号(如中断、终止、非法操作等)设置一个自定义的处理函数,从而改变程序收到该信号时的默认行为。

  • 捕获信号:让程序在收到某个信号时,执行你写的代码(例如清理资源、记录日志、忽略信号)。

  • 恢复默认:把某个信号的处理方式恢复为系统默认动作。

  • 忽略信号:让程序忽略某些信号(例如SIGINT按 Ctrl+C 时不中断)。

#include <signal.h>

void (*signal(int sig, void (*handler)(int)))(int);
// 更易理解的版本:
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

  • sig:要处理的信号编号,例如:

    • SIGINT(Ctrl+C 中断信号)

    • SIGTERM(终止信号)

    • SIGSEGV(段错误,非法内存访问)

  • handler:三种取值之一:

    • SIG_IGN→ 忽略该信号

    • SIG_DFL→ 恢复默认处理(通常是终止程序)

    • 自定义函数指针 → 执行你写的处理逻辑

2.kill

kill的作用是:向一个进程发送信号。它不一定是"杀死"进程,而是告诉进程"你该做什么"。

#include <sys/types.h>
#include <signal.h>

int kill(pid_t pid, int sig);

参数详解

第一个参数:pid_t pid(目标进程)

pid 值含义
> 0发送给指定 PID 的单个进程
== 0发送给当前进程所在进程组的所有进程
== -1发送给调用进程有权发送信号的所有进程(不包括 init/systemd 进程)
< -1发送给进程组 ID = |pid|的所有进程(如 pid=-1234,发给进程组1234)

第二个参数:int sig(信号编号)

含义
0空信号,不真正发送,仅用于检查进程是否存在
1~31标准 Unix 信号(如 9=SIGKILL, 15=SIGTERM)
34~64实时信号(Linux 扩展)
返回值含义
0成功。至少有一个信号被成功发送
-1失败。此时需要查看errno获取具体错误原因

3.raise

raise()是一个库函数,用于进程向自己发送信号

与 kill() 的区别

函数发送方向
kill()其他进程自己发送信号
raise()只能向自己发送信号
#include <signal.h>
int raise(int sig);
参数含义
sig要发送的信号编号(如SIGTERMSIGKILLSIGINT
返回值含义
0成功
非0失败

4.abord

abort()是一个库函数,用于异常终止当前进程,并生成 core dump(核心转储文件)用于调试。

abort()让程序非正常崩溃,而不是正常退出。

#include <stdlib.h>
void abort(void);

注意:abort()没有返回值,因为它永远不会正常返回。

他对应的是6号。

5.alarm

alarm()是一个系统调用,用于设置一个定时器,在指定秒数后向自己发送SIGALRM信号。

设置一个闹钟,N 秒后给自己发一个SIGALRM信号

#include <unistd.h>
unsigned int alarm(unsigned int seconds);
参数含义
seconds定时秒数,0 表示取消之前的闹钟
返回值含义
0之前没有设置过闹钟
>0之前闹钟剩余的秒数(如果之前有未触发的闹钟)
  1. 每个进程只有一个闹钟:再次调用alarm()重置之前的闹钟

  2. 到达指定时间后,进程收到SIGALRM信号(默认行为是终止进程)

  3. 如果seconds = 0:取消当前闹钟,不设置新闹钟

6.pause

pause()是一个系统调用,用于让进程挂起(睡眠),直到收到一个信号。

让进程停下来睡觉,直到被信号唤醒。

#include <unistd.h>
int pause(void);

返回值含义
-1总是返回 -1(因为被信号中断)

注意:pause()永远不返回 0,它只会在收到信号后返回 -1,并设置errnoEINTR

errno含义
EINTR被信号中断(正常情况)
  1. 调用pause()的进程会一直挂起(进入睡眠状态)

  2. 进程不占用 CPU 时间

  3. 直到收到一个信号,并且该信号的处理函数执行完毕后,pause()才返回

  4. 如果信号默认行为是终止进程,则pause()永远不会返回

7.sigaction

sigaction是一个功能强大且灵活的 POSIX 系统调用,用于检查和更改进程接收到特定信号时的行为。与signal函数相比,它提供了更精细的控制、更好的跨平台移植性,是编写健壮信号处理程序的推荐方法

#include <signal.h> int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
  • signum:指定要操作的信号,可以是除SIGKILLSIGSTOP之外的任何信号。

  • act:如果非空,则指向一个struct sigaction结构体,用于设置新的信号处理行为。

  • oldact:如果非空,则用于保存之前的信号处理行为,方便之后恢复。

返回值:成功时返回0,失败时返回-1并设置errno以指示错误

🏗️ 核心数据结构:struct sigaction

这是sigaction的核心,其定义大致如下:

struct sigaction { void (*sa_handler)(int); // 简单的信号处理函数指针 void (*sa_sigaction)(int, siginfo_t *, void *); // 可接收额外信息的处理函数 sigset_t sa_mask; // 处理函数执行时要额外阻塞的信号集 int sa_flags; // 用于修改信号行为的标志位 void (*sa_restorer)(void); // 已废弃,仅供内部使用,无需关注 };

void (*sa_handler)(int);这个就是我们在signal中的hander函数。

三.sigset_t

sigset_t是一个信号集类型,用于表示多个信号的集合。

头文件:

#include <signal.h>

五个核心函数

函数功能相当于位操作
sigemptyset()清空信号集(全部置0)set = 0
sigfillset()填满信号集(全部置1)set = ~0
sigaddset()添加一个信号(置1)set |= (1 << sig)
sigdelset()删除一个信号(置0)set &= ~(1 << sig)
sigismember()测试信号是否存在(读位)(set >> sig) & 1

1.sigprocmask():修改block表

sigprocmask()是一个系统调用,用于读取或修改进程的信号屏蔽字,决定哪些信号被阻塞(暂时不递送)。设置或获取进程的"信号黑名单",被屏蔽的信号暂时不会被进程处理。

#include <signal.h>int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

第一个参数:how(操作方式)

how 值含义公式
SIG_BLOCKset中的信号添加到当前屏蔽字mask = mask | set
SIG_UNBLOCKset中的信号从当前屏蔽字移除mask = mask & ~set
SIG_SETMASK将当前屏蔽字设置setmask = set

第二个参数:set(新屏蔽集)

  • 指向要设置的信号集

  • 可以为NULL(此时how被忽略,用于仅查询)

第三个参数:oldset(旧屏蔽集)

  • 用于保存修改前的信号屏蔽字

  • 可以为NULL(不保存旧值)


返回值

返回值含义
0成功
-1失败,并设置errno

错误码

errno含义
EINVALhow参数无效
EFAULTsetoldset指针无效

每个进程都有一个信号屏蔽字,是一个信号集,表示当前被阻塞的信号

sigset_t pending; // 被阻塞的信号会进入"待处理"状态

重要规则

  • 被屏蔽的信号不会丢失,只是暂时不递送

  • 当解除屏蔽后,信号会被递送

  • SIGKILLSIGSTOP不能被屏蔽

2.sigpending():pending表

sigpending()是一个系统调用,用于获取进程当前被阻塞(挂起)的待处理信号

查看哪些信号被阻塞了但还没有被处理(即已经到达但因为被屏蔽而排队等待的信号)。

#include <signal.h>
int sigpending(sigset_t *set);
参数含义
set指向sigset_t的指针,用于返回当前待处理的信号集
返回值含义
0成功
-1失败,并设置errno

注意:在 Linux 中,sigpending()总是成功(返回 0),但为了可移植性,仍应检查返回值。

信号生命周期: 发送信号 → 是否被屏蔽? ↓ ↓ 否 是 ↓ ↓ 立即递送 进入"待处理"队列 给进程处理 (pending状态) ↓ 解除屏蔽后 ↓ 立即递送

关键点

  • 待处理信号:已经发送给进程,但因为被屏蔽,暂时无法递送

  • 每个信号在待处理队列中只有一个(重复发送不会排队多次)

  • 解除屏蔽后,待处理信号会立即被递送

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/5 7:06:49

5个步骤轻松实现Unity游戏自动翻译:XUnity.AutoTranslator完全指南

5个步骤轻松实现Unity游戏自动翻译&#xff1a;XUnity.AutoTranslator完全指南 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator XUnity.AutoTranslator是一款功能强大的Unity游戏自动翻译插件&#xff0c;…

作者头像 李华
网站建设 2026/5/5 7:05:28

OPC Team:从角色扮演到工程化执行的AI Agent协作框架实战

1. 项目概述&#xff1a;从“角色扮演”到“工程化执行”的Agent协作框架如果你和我一样&#xff0c;在过去一年里尝试过各种AI Agent框架&#xff0c;大概率会陷入一个怪圈&#xff1a;花大量时间设计精美的角色设定和复杂的Prompt&#xff0c;但Agent的执行过程依然像一场“黑…

作者头像 李华
网站建设 2026/5/5 7:03:29

RAISECITY框架:基于多模态LLM的智能3D城市生成技术

1. 项目背景与核心价值 去年参与某新区数字孪生项目时&#xff0c;我们团队曾为制作3D城市模型耗费了整整三个月时间。测绘车跑遍每条街道&#xff0c;建模师手动调整每栋建筑&#xff0c;最终交付的模型却仍存在植被分布不合理、交通流线反常识等问题。这种传统建模方式的高成…

作者头像 李华
网站建设 2026/5/5 7:02:27

Power Apps上传文件到SharePoint时,Base64转换和JSON解析的坑我都帮你踩过了

Power Apps文件上传实战&#xff1a;避开Base64与JSON解析的十大深坑 当你第一次在Power Apps中尝试将文件上传到SharePoint时&#xff0c;那种看似简单的操作背后隐藏着无数可能让你熬夜调试的陷阱。作为经历过无数次失败的老兵&#xff0c;我想带你直击那些官方文档从未提及的…

作者头像 李华