信号是Linux/Unix系统中进程间通信的一种异步通知机制,也是操作系统响应某些事件时对进程产生的中断。对于刚接触Linux编程的朋友来说,理解信号如何在内核中被保存、阻塞以及最终处理,是掌握系统编程的关键一步。本文将用最通俗的语言,带你彻底搞懂Linux信号的信号保存与信号处理的全过程。
信号可以来自多种场景:
SIGFPE(浮点异常)信号。alarm定时器到期,内核向进程发送SIGALRM信号。SIGINT信号。kill、raise等函数主动发送信号。
每个进程在内核中都有两个关键的位图结构:未决信号集(pending) 和 阻塞信号集(blocked),它们共同决定了信号的信号保存状态。
小知识:阻塞信号集也称为“信号屏蔽字”,可以通过sigprocmask系统调用来修改。而pending集只能由内核更新,但进程可以通过sigpending函数读取。
为了便于操作这两个位图,Linux提供了一套信号集操作函数。它们不是直接修改内核位图,而是用于在用户空间构造sigset_t类型的变量,然后通过系统调用传递给内核。
#include sigset_t set;sigemptyset(&set); // 清空集合sigaddset(&set, SIGINT); // 将SIGINT加入集合sigdelset(&set, SIGINT); // 将SIGINT从集合移除sigismember(&set, SIGINT); // 测试SIGINT是否在集合中// 将用户空间的set设置给内核的阻塞信号集sigprocmask(SIG_BLOCK, &set, NULL); 通过sigprocmask,我们可以动态地阻塞或解除阻塞某些信号,从而影响信号的信号处理时机。
当一个信号要递送给进程时,内核会根据当前状态决定如何处理:
signal或sigaction注册了自定义处理函数,则当信号递送时,内核会暂停当前执行流,跳转到用户态执行该处理函数,返回后再恢复。注意:只有未被阻塞的信号才有机会被递送。当信号递送时,pending位被清0,然后执行对应的处理动作。
假设进程正在执行main函数中的代码,此时一个信号产生:
如果信号在阻塞期间多次产生,对于普通信号(非实时信号),pending位图中只记录一次,即相同信号只被保存一次;而对于实时信号,则会排队保存多次。本文主要讨论标准Linux信号(1~31),它们都是非实时信号。
signal和sigaction用于注册处理函数;sigprocmask用于操作阻塞信号集;sigpending用于查看未决信号。希望这篇文章能帮你理清Linux信号中信号保存与信号处理的底层逻辑!
本文由主机测评网于2026-02-14发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://vpshk.cn/20260225135.html