/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}

大家好,欢迎来到 huangjin007_ 的博客
⭐
个人主页:huangjin007_
🔥
文章收录专栏:Linux 内功修炼手册(系统篇)
总会有一些坚持能从冰封的土地里培育出十万朵怒放的蔷薇
Linux 系统篇(三十七) —— 信号是如何保存的?
文章目录
- Linux 系统篇(三十七) —— 信号是如何保存的?
-
- 一、信号产生之后,去哪儿了?
- 二、信号相关的四个核心概念
-
- 2.1 信号递达(Delivery)
- 2.2 信号未决(Pending)
- 2.3 信号阻塞(Block)
- 2.4 阻塞和忽略有什么区别?
- 三、内核如何保存信号?
-
- 3.1 三种信息分别记录什么?
- 3.2 Block:阻塞信号集
- 3.3 Pending:未决信号集
- 3.4 Handler:信号处理动作
- 四、三种信息如何配合工作?
- 五、sigset_t:信号集
-
- 5.1 sigset_t 是什么?
- 六、信号集操作函数
-
- 6.1 sigemptyset:清空信号集
- 6.2 sigfillset:填满信号集
- 6.3 sigaddset:向信号集中添加信号
- 6.4 sigdelset:从信号集中删除信号
- 6.5 sigismember:判断信号是否在信号集中
- 6.6 函数总结
- 七、sigprocmask:修改进程的阻塞信号集
-
- 7.1 参数介绍
- 7.2 参数二:set
- 7.3 参数三:oldset
- 7.4 返回值
- 八、sigpending:读取未决信号集
- 九、动手实验:阻塞 SIGINT,观察 Pending 的变化
-
- 9.1 实验目标
- 9.2 完整代码
- 9.3 实验现象
- 9.4 为什么 Ctrl+\\ 仍然可以终止程序?
- 十、常规信号为什么会丢失?
-
- 10.1 实时信号可以排队
- 十一、Core Dump:进程异常终止时留下的调试信息
-
- 11.1 为什么没有生成 core 文件?
- 11.2 使用 GDB 调试 core 文件
- 11.3 waitpid 如何判断是否产生 Core?
- 十二、本篇总结
-
- 12.1 三个核心信息
- 12.2 常用函数
- 12.3 信号产生到递达的完整流程
- 12.4 面试易错点
- 结语:
一、信号产生之后,去哪儿了?
在上一篇文章中,我们已经知道了信号可以通过多种方式产生:
- 按下 Ctrl+C,产生 SIGINT 信号;
- 使用 kill 命令,向指定进程发送信号;
- 调用 alarm(),在指定时间后产生 SIGALRM 信号;
- 发生除零、非法内存访问等硬件异常,也可能产生对应信号。
但是,这里有一个问题:
信号产生之后,操作系统会立即处理它吗?
答案是:不一定。
我们可以想象这样一个场景:
你正在开会,手机突然收到一条消息。可是你现在正在发言,不能立刻查看手机,于是先把消息放在那里,等有空了再处理。
Linux 信号也有类似的机制。
信号产生之后,不一定能够立即递达。如果暂时不能处理,内核就会先把它记录下来,等到合适的时机再处理。
那么,内核究竟是怎么记录这些信号的呢?
在正式学习之前,我们先认识几个非常重要的概念。
二、信号相关的四个核心概念
2.1 信号递达(Delivery)
实际执行信号处理动作的过程,称为信号递达(Delivery)。
比如:
signal(SIGINT, handler);
void handler(int signo)
{
cout << "收到 SIGINT 信号" << endl;
}
当 SIGINT 信号最终被处理,执行对应的处理动作时,就发生了信号递达。
这里的处理动作有三种:
这些处理动作在第一篇中已经介绍过,这里不再展开。
2.2 信号未决(Pending)
信号从产生到递达之间的状态,称为信号未决(Pending)。
简单理解:
信号已经产生了,但是还没有被处理,这个信号就处于未决状态。
例如:
#mermaid-svg-TMhcpkdB24F84V5E{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-TMhcpkdB24F84V5E .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TMhcpkdB24F84V5E .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TMhcpkdB24F84V5E .error-icon{fill:#552222;}#mermaid-svg-TMhcpkdB24F84V5E .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TMhcpkdB24F84V5E .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TMhcpkdB24F84V5E .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TMhcpkdB24F84V5E .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TMhcpkdB24F84V5E .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TMhcpkdB24F84V5E .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TMhcpkdB24F84V5E .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TMhcpkdB24F84V5E .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TMhcpkdB24F84V5E .marker.cross{stroke:#333333;}#mermaid-svg-TMhcpkdB24F84V5E svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TMhcpkdB24F84V5E p{margin:0;}#mermaid-svg-TMhcpkdB24F84V5E .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-TMhcpkdB24F84V5E .cluster-label text{fill:#333;}#mermaid-svg-TMhcpkdB24F84V5E .cluster-label span{color:#333;}#mermaid-svg-TMhcpkdB24F84V5E .cluster-label span p{background-color:transparent;}#mermaid-svg-TMhcpkdB24F84V5E .label text,#mermaid-svg-TMhcpkdB24F84V5E span{fill:#333;color:#333;}#mermaid-svg-TMhcpkdB24F84V5E .node rect,#mermaid-svg-TMhcpkdB24F84V5E .node circle,#mermaid-svg-TMhcpkdB24F84V5E .node ellipse,#mermaid-svg-TMhcpkdB24F84V5E .node polygon,#mermaid-svg-TMhcpkdB24F84V5E .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TMhcpkdB24F84V5E .rough-node .label text,#mermaid-svg-TMhcpkdB24F84V5E .node .label text,#mermaid-svg-TMhcpkdB24F84V5E .image-shape .label,#mermaid-svg-TMhcpkdB24F84V5E .icon-shape .label{text-anchor:middle;}#mermaid-svg-TMhcpkdB24F84V5E .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-TMhcpkdB24F84V5E .rough-node .label,#mermaid-svg-TMhcpkdB24F84V5E .node .label,#mermaid-svg-TMhcpkdB24F84V5E .image-shape .label,#mermaid-svg-TMhcpkdB24F84V5E .icon-shape .label{text-align:center;}#mermaid-svg-TMhcpkdB24F84V5E .node.clickable{cursor:pointer;}#mermaid-svg-TMhcpkdB24F84V5E .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-TMhcpkdB24F84V5E .arrowheadPath{fill:#333333;}#mermaid-svg-TMhcpkdB24F84V5E .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-TMhcpkdB24F84V5E .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-TMhcpkdB24F84V5E .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TMhcpkdB24F84V5E .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-TMhcpkdB24F84V5E .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TMhcpkdB24F84V5E .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-TMhcpkdB24F84V5E .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-TMhcpkdB24F84V5E .cluster text{fill:#333;}#mermaid-svg-TMhcpkdB24F84V5E .cluster span{color:#333;}#mermaid-svg-TMhcpkdB24F84V5E div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-TMhcpkdB24F84V5E .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-TMhcpkdB24F84V5E rect.text{fill:none;stroke-width:0;}#mermaid-svg-TMhcpkdB24F84V5E .icon-shape,#mermaid-svg-TMhcpkdB24F84V5E .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TMhcpkdB24F84V5E .icon-shape p,#mermaid-svg-TMhcpkdB24F84V5E .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-TMhcpkdB24F84V5E .icon-shape .label rect,#mermaid-svg-TMhcpkdB24F84V5E .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TMhcpkdB24F84V5E .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-TMhcpkdB24F84V5E .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-TMhcpkdB24F84V5E :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-TMhcpkdB24F84V5E .startNode>*{fill:#F2F4F7!important;stroke:#9CA3AF!important;stroke-width:2px!important;color:#333!important;}#mermaid-svg-TMhcpkdB24F84V5E .startNode span{fill:#F2F4F7!important;stroke:#9CA3AF!important;stroke-width:2px!important;color:#333!important;}#mermaid-svg-TMhcpkdB24F84V5E .startNode tspan{fill:#333!important;}#mermaid-svg-TMhcpkdB24F84V5E .processNode>*{fill:#E0F2FE!important;stroke:#7DD3FC!important;stroke-width:1px!important;color:#333!important;}#mermaid-svg-TMhcpkdB24F84V5E .processNode span{fill:#E0F2FE!important;stroke:#7DD3FC!important;stroke-width:1px!important;color:#333!important;}#mermaid-svg-TMhcpkdB24F84V5E .processNode tspan{fill:#333!important;}#mermaid-svg-TMhcpkdB24F84V5E .pendingNode>*{fill:#FFE4E6!important;stroke:#FDA4AF!important;stroke-width:2px!important;color:#333!important;}#mermaid-svg-TMhcpkdB24F84V5E .pendingNode span{fill:#FFE4E6!important;stroke:#FDA4AF!important;stroke-width:2px!important;color:#333!important;}#mermaid-svg-TMhcpkdB24F84V5E .pendingNode tspan{fill:#333!important;}#mermaid-svg-TMhcpkdB24F84V5E .deliverNode>*{fill:#DCFCE7!important;stroke:#86EFAC!important;stroke-width:2px!important;color:#333!important;}#mermaid-svg-TMhcpkdB24F84V5E .deliverNode span{fill:#DCFCE7!important;stroke:#86EFAC!important;stroke-width:2px!important;color:#333!important;}#mermaid-svg-TMhcpkdB24F84V5E .deliverNode tspan{fill:#333!important;}
SIGINT 信号产生
信号暂时没有被处理
信号处于未决状态 (Pending)
最终执行信号处理动作
信号递达 (Delivery)
注意:
未决描述的是一种状态,而不是一种处理动作。
2.3 信号阻塞(Block)
进程可以选择阻塞某个信号。
阻塞可以理解为:
进程主动告诉操作系统:
这个信号先别处理,暂时放一放。
例如,我们可以选择阻塞 SIGINT:
sigset_t block_set;
sigemptyset(&block_set);
sigaddset(&block_set, SIGINT);
不过,这里只是准备好了一个信号集,还没有真正阻塞信号。
真正修改进程信号屏蔽字,需要使用后面要学习的 sigprocmask()。
当一个信号被阻塞时,即使它产生了,也不会立即递达,而是保持未决状态。
等到解除阻塞之后,内核才有机会递达这个信号。
2.4 阻塞和忽略有什么区别?
两者看起来都可能导致进程没有执行对应的信号处理函数,但它们发生的阶段完全不同。
| 发生阶段 | 递达之前 | 递达时 |
| 信号是否递达 | 不会递达 | 已经递达 |
| 信号状态 | 保持未决 | 不再等待处理 |
| 能否改变处理动作 | 可以在递达前修改 | 需要重新设置处理动作 |
举个例子:
假设我们把 SIGINT 设置为忽略:
signal(SIGINT, SIG_IGN);
此时按下 Ctrl+C,信号递达后执行忽略动作,进程不会因为这个信号而终止。
但是,如果我们阻塞了 SIGINT:
sigprocmask(SIG_BLOCK, &block_set, nullptr);
此时按下 Ctrl+C,信号会进入未决状态,而不是直接被忽略。
三、内核如何保存信号?
前面介绍了三个概念:
- Block:信号是否被阻塞;
- Pending:信号是否处于未决状态;
- Handler:信号应该如何处理。
为了方便理解,我们可以把它们看成内核为信号维护的三类信息。
3.1 三种信息分别记录什么?
假设一个进程收到了 SIGINT 信号。
内核需要知道:
因此,可以用下面的概念图来理解:
#mermaid-svg-Vp4bFYjdbNz7YuZy{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Vp4bFYjdbNz7YuZy .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Vp4bFYjdbNz7YuZy .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Vp4bFYjdbNz7YuZy .error-icon{fill:#552222;}#mermaid-svg-Vp4bFYjdbNz7YuZy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Vp4bFYjdbNz7YuZy .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Vp4bFYjdbNz7YuZy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Vp4bFYjdbNz7YuZy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Vp4bFYjdbNz7YuZy .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Vp4bFYjdbNz7YuZy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Vp4bFYjdbNz7YuZy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Vp4bFYjdbNz7YuZy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Vp4bFYjdbNz7YuZy .marker.cross{stroke:#333333;}#mermaid-svg-Vp4bFYjdbNz7YuZy svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Vp4bFYjdbNz7YuZy p{margin:0;}#mermaid-svg-Vp4bFYjdbNz7YuZy .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-Vp4bFYjdbNz7YuZy .cluster-label text{fill:#333;}#mermaid-svg-Vp4bFYjdbNz7YuZy .cluster-label span{color:#333;}#mermaid-svg-Vp4bFYjdbNz7YuZy .cluster-label span p{background-color:transparent;}#mermaid-svg-Vp4bFYjdbNz7YuZy .label text,#mermaid-svg-Vp4bFYjdbNz7YuZy span{fill:#333;color:#333;}#mermaid-svg-Vp4bFYjdbNz7YuZy .node rect,#mermaid-svg-Vp4bFYjdbNz7YuZy .node circle,#mermaid-svg-Vp4bFYjdbNz7YuZy .node ellipse,#mermaid-svg-Vp4bFYjdbNz7YuZy .node polygon,#mermaid-svg-Vp4bFYjdbNz7YuZy .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Vp4bFYjdbNz7YuZy .rough-node .label text,#mermaid-svg-Vp4bFYjdbNz7YuZy .node .label text,#mermaid-svg-Vp4bFYjdbNz7YuZy .image-shape .label,#mermaid-svg-Vp4bFYjdbNz7YuZy .icon-shape .label{text-anchor:middle;}#mermaid-svg-Vp4bFYjdbNz7YuZy .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Vp4bFYjdbNz7YuZy .rough-node .label,#mermaid-svg-Vp4bFYjdbNz7YuZy .node .label,#mermaid-svg-Vp4bFYjdbNz7YuZy .image-shape .label,#mermaid-svg-Vp4bFYjdbNz7YuZy .icon-shape .label{text-align:center;}#mermaid-svg-Vp4bFYjdbNz7YuZy .node.clickable{cursor:pointer;}#mermaid-svg-Vp4bFYjdbNz7YuZy .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Vp4bFYjdbNz7YuZy .arrowheadPath{fill:#333333;}#mermaid-svg-Vp4bFYjdbNz7YuZy .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Vp4bFYjdbNz7YuZy .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Vp4bFYjdbNz7YuZy .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Vp4bFYjdbNz7YuZy .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Vp4bFYjdbNz7YuZy .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Vp4bFYjdbNz7YuZy .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Vp4bFYjdbNz7YuZy .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Vp4bFYjdbNz7YuZy .cluster text{fill:#333;}#mermaid-svg-Vp4bFYjdbNz7YuZy .cluster span{color:#333;}#mermaid-svg-Vp4bFYjdbNz7YuZy div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Vp4bFYjdbNz7YuZy .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Vp4bFYjdbNz7YuZy rect.text{fill:none;stroke-width:0;}#mermaid-svg-Vp4bFYjdbNz7YuZy .icon-shape,#mermaid-svg-Vp4bFYjdbNz7YuZy .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Vp4bFYjdbNz7YuZy .icon-shape p,#mermaid-svg-Vp4bFYjdbNz7YuZy .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Vp4bFYjdbNz7YuZy .icon-shape .label rect,#mermaid-svg-Vp4bFYjdbNz7YuZy .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Vp4bFYjdbNz7YuZy .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Vp4bFYjdbNz7YuZy .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Vp4bFYjdbNz7YuZy :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-Vp4bFYjdbNz7YuZy .rootNode>*{fill:#F8FAFC!important;stroke:#94A3B8!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-Vp4bFYjdbNz7YuZy .rootNode span{fill:#F8FAFC!important;stroke:#94A3B8!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-Vp4bFYjdbNz7YuZy .rootNode tspan{fill:#333!important;}#mermaid-svg-Vp4bFYjdbNz7YuZy .blockNode>*{fill:#E0F2FE!important;stroke:#7DD3FC!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-Vp4bFYjdbNz7YuZy .blockNode span{fill:#E0F2FE!important;stroke:#7DD3FC!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-Vp4bFYjdbNz7YuZy .blockNode tspan{fill:#333!important;}#mermaid-svg-Vp4bFYjdbNz7YuZy .pendingNode>*{fill:#FFE4E6!important;stroke:#FDA4AF!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-Vp4bFYjdbNz7YuZy .pendingNode span{fill:#FFE4E6!important;stroke:#FDA4AF!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-Vp4bFYjdbNz7YuZy .pendingNode tspan{fill:#333!important;}#mermaid-svg-Vp4bFYjdbNz7YuZy .handlerNode>*{fill:#DCFCE7!important;stroke:#86EFAC!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-Vp4bFYjdbNz7YuZy .handlerNode span{fill:#DCFCE7!important;stroke:#86EFAC!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-Vp4bFYjdbNz7YuZy .handlerNode tspan{fill:#333!important;}#mermaid-svg-Vp4bFYjdbNz7YuZy .questionNode>*{fill:#FFFFFF!important;stroke:#CBD5E1!important;stroke-width:1.5px!important;stroke-dasharray:4 4!important;color:#555!important;rx:4!important;ry:4!important;}#mermaid-svg-Vp4bFYjdbNz7YuZy .questionNode span{fill:#FFFFFF!important;stroke:#CBD5E1!important;stroke-width:1.5px!important;stroke-dasharray:4 4!important;color:#555!important;rx:4!important;ry:4!important;}#mermaid-svg-Vp4bFYjdbNz7YuZy .questionNode tspan{fill:#555!important;}
进程的信号相关信息
Block 阻塞信号集
Pending 未决信号集
Handler 处理动作
是否被阻塞?
是否已经产生?
应该如何处理?

3.2 Block:阻塞信号集
阻塞信号集记录:
哪些信号当前被进程阻塞了。
例如:
| SIGHUP(1) | 0 |
| SIGINT(2) | 1 |
| SIGQUIT(3) | 0 |
其中:
- 0:没有阻塞;
- 1:已经阻塞。
上面的表格表示:
SIGINT 被阻塞,而 SIGHUP 和 SIGQUIT 没有被阻塞。
阻塞信号集也叫作:
信号屏蔽字(Signal Mask)。
这里的屏蔽,指的是阻止信号递达,而不是忽略信号。
3.3 Pending:未决信号集
未决信号集记录:
哪些信号已经产生,但是还没有递达。
例如:
| SIGHUP(1) | 0 |
| SIGINT(2) | 1 |
| SIGQUIT(3) | 0 |
表示:
SIGINT 已经产生,但是还没有被递达。
为什么会出现这种情况?
因为信号可能被阻塞了。
例如:
#mermaid-svg-fReDvmQlq3U4lzAV{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-fReDvmQlq3U4lzAV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-fReDvmQlq3U4lzAV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-fReDvmQlq3U4lzAV .error-icon{fill:#552222;}#mermaid-svg-fReDvmQlq3U4lzAV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-fReDvmQlq3U4lzAV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-fReDvmQlq3U4lzAV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-fReDvmQlq3U4lzAV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-fReDvmQlq3U4lzAV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-fReDvmQlq3U4lzAV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-fReDvmQlq3U4lzAV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-fReDvmQlq3U4lzAV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-fReDvmQlq3U4lzAV .marker.cross{stroke:#333333;}#mermaid-svg-fReDvmQlq3U4lzAV svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-fReDvmQlq3U4lzAV p{margin:0;}#mermaid-svg-fReDvmQlq3U4lzAV .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-fReDvmQlq3U4lzAV .cluster-label text{fill:#333;}#mermaid-svg-fReDvmQlq3U4lzAV .cluster-label span{color:#333;}#mermaid-svg-fReDvmQlq3U4lzAV .cluster-label span p{background-color:transparent;}#mermaid-svg-fReDvmQlq3U4lzAV .label text,#mermaid-svg-fReDvmQlq3U4lzAV span{fill:#333;color:#333;}#mermaid-svg-fReDvmQlq3U4lzAV .node rect,#mermaid-svg-fReDvmQlq3U4lzAV .node circle,#mermaid-svg-fReDvmQlq3U4lzAV .node ellipse,#mermaid-svg-fReDvmQlq3U4lzAV .node polygon,#mermaid-svg-fReDvmQlq3U4lzAV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-fReDvmQlq3U4lzAV .rough-node .label text,#mermaid-svg-fReDvmQlq3U4lzAV .node .label text,#mermaid-svg-fReDvmQlq3U4lzAV .image-shape .label,#mermaid-svg-fReDvmQlq3U4lzAV .icon-shape .label{text-anchor:middle;}#mermaid-svg-fReDvmQlq3U4lzAV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-fReDvmQlq3U4lzAV .rough-node .label,#mermaid-svg-fReDvmQlq3U4lzAV .node .label,#mermaid-svg-fReDvmQlq3U4lzAV .image-shape .label,#mermaid-svg-fReDvmQlq3U4lzAV .icon-shape .label{text-align:center;}#mermaid-svg-fReDvmQlq3U4lzAV .node.clickable{cursor:pointer;}#mermaid-svg-fReDvmQlq3U4lzAV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-fReDvmQlq3U4lzAV .arrowheadPath{fill:#333333;}#mermaid-svg-fReDvmQlq3U4lzAV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-fReDvmQlq3U4lzAV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-fReDvmQlq3U4lzAV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fReDvmQlq3U4lzAV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-fReDvmQlq3U4lzAV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fReDvmQlq3U4lzAV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-fReDvmQlq3U4lzAV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-fReDvmQlq3U4lzAV .cluster text{fill:#333;}#mermaid-svg-fReDvmQlq3U4lzAV .cluster span{color:#333;}#mermaid-svg-fReDvmQlq3U4lzAV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-fReDvmQlq3U4lzAV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-fReDvmQlq3U4lzAV rect.text{fill:none;stroke-width:0;}#mermaid-svg-fReDvmQlq3U4lzAV .icon-shape,#mermaid-svg-fReDvmQlq3U4lzAV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fReDvmQlq3U4lzAV .icon-shape p,#mermaid-svg-fReDvmQlq3U4lzAV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-fReDvmQlq3U4lzAV .icon-shape .label rect,#mermaid-svg-fReDvmQlq3U4lzAV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fReDvmQlq3U4lzAV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-fReDvmQlq3U4lzAV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-fReDvmQlq3U4lzAV :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-fReDvmQlq3U4lzAV .sourceNode>*{fill:#FFF3E0!important;stroke:#FFB74D!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-fReDvmQlq3U4lzAV .sourceNode span{fill:#FFF3E0!important;stroke:#FFB74D!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-fReDvmQlq3U4lzAV .sourceNode tspan{fill:#333!important;}#mermaid-svg-fReDvmQlq3U4lzAV .actionNode>*{fill:#E3F2FD!important;stroke:#64B5F6!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-fReDvmQlq3U4lzAV .actionNode span{fill:#E3F2FD!important;stroke:#64B5F6!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-fReDvmQlq3U4lzAV .actionNode tspan{fill:#333!important;}#mermaid-svg-fReDvmQlq3U4lzAV .blockedNode>*{fill:#FFE4E6!important;stroke:#FDA4AF!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-fReDvmQlq3U4lzAV .blockedNode span{fill:#FFE4E6!important;stroke:#FDA4AF!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-fReDvmQlq3U4lzAV .blockedNode tspan{fill:#333!important;}#mermaid-svg-fReDvmQlq3U4lzAV .pendingNode>*{fill:#F3E8FF!important;stroke:#D8B4FE!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-fReDvmQlq3U4lzAV .pendingNode span{fill:#F3E8FF!important;stroke:#D8B4FE!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-fReDvmQlq3U4lzAV .pendingNode tspan{fill:#333!important;}#mermaid-svg-fReDvmQlq3U4lzAV .resultNode>*{fill:#F1F5F9!important;stroke:#94A3B8!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-fReDvmQlq3U4lzAV .resultNode span{fill:#F1F5F9!important;stroke:#94A3B8!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-fReDvmQlq3U4lzAV .resultNode tspan{fill:#333!important;}
SIGINT 产生
检查 Block
发现 SIGINT 被阻塞
Pending 对应位置 1
暂时不能递达
因此:
信号被阻塞时,产生的信号会保持在未决状态。
3.4 Handler:信号处理动作
Handler 记录的是:
每一种信号应该执行什么处理动作。
例如:
| SIGHUP | SIG_DFL |
| SIGINT | SIG_IGN |
| SIGQUIT | 自定义函数 sighandler |
这里的处理动作有三种:
SIG_DFL // 默认处理动作
SIG_IGN // 忽略信号
handler // 用户自定义处理函数
例如:
signal(SIGINT, SIG_IGN);
表示把 SIGINT 对应的处理动作设置为忽略。
而:
signal(SIGINT, SIG_DFL);
表示恢复 SIGINT 的默认处理动作。
至于:
signal(SIGINT, handler);
则表示使用用户自定义的处理函数。
这里可以把 Handler 理解成一份信号处理规则表:信号递达时,内核根据对应的处理动作进行处理。
四、三种信息如何配合工作?
现在我们把 Block、Pending 和 Handler 放在一起。
假设当前进程的状态如下:
| SIGHUP(1) | 0 | 0 | SIG_DFL |
| SIGINT(2) | 1 | 1 | SIG_IGN |
| SIGQUIT(3) | 1 | 0 | handler |
我们逐个分析。
情况一:SIGHUP
Block = 0
Pending = 0
Handler = SIG_DFL
表示:
没有阻塞,也没有产生过该信号。
因此当前没有需要处理的事情。
情况二:SIGINT
Block = 1
Pending = 1
Handler = SIG_IGN
表示:
SIGINT 已经产生,但是被阻塞了。
因此它只能保持未决状态,暂时不能递达。
虽然它的处理动作是忽略,但此时还轮不到执行忽略动作。
因为:
只要信号还处于阻塞状态,就不会递达。
情况三:SIGQUIT
Block = 1
Pending = 0
Handler = handler
表示:
SIGQUIT 被阻塞了,但是还没有产生。
因此它既不需要处理,也没有进入未决状态。
通过这三个例子,我们就能理解:
Block 决定信号能不能递达,Pending 记录信号有没有产生但尚未递达,Handler 决定递达时执行什么动作。
五、sigset_t:信号集
前面提到了 Block 和 Pending,它们都可以用位图的形式表示。
例如:
| Block | 0 | 1 🔴 | 0 | 0 | 1 🔴 |
| Pending | 0 | 1 🔵 | 1 🔵 | 0 | 0 |
可以看到,每个信号只需要一个 bit,就能表示它当前对应的状态。
- 在 Block 中,1 表示该信号被阻塞;
- 在 Pending 中,1 表示该信号处于未决状态。
既然都可以使用位图表示,那么 Linux 就提供了一个信号集类型:
sigset_t
它用来表示一组信号。
5.1 sigset_t 是什么?
sigset_t 是系统提供的信号集类型。
我们可以通过它保存一组信号,然后把这个信号集交给相关系统调用进行操作。
例如:
sigset_t set;
定义了一个信号集变量。
注意:
不要自己猜测 sigset_t 内部究竟是几个整数,也不要直接打印它的内存内容。
它的内部实现由系统决定。
我们只需要使用系统提供的函数操作它即可。
六、信号集操作函数
Linux 提供了五个常用函数,用于操作 sigset_t。
#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);
6.1 sigemptyset:清空信号集
int sigemptyset(sigset_t *set);
作用:
初始化信号集,使其中不包含任何信号。
例如:
sigset_t set;
sigemptyset(&set);
执行之后:
set = {}
表示当前信号集为空。
6.2 sigfillset:填满信号集
int sigfillset(sigset_t *set);
作用:
初始化信号集,使其包含系统支持的所有信号。
例如:
sigset_t set;
sigfillset(&set);
可以理解为:
set = {系统支持的所有信号}
注意,某些信号不能被阻塞,例如 SIGKILL 和 SIGSTOP。即使它们出现在信号集中,也不能通过屏蔽字真正阻塞它们。
6.3 sigaddset:向信号集中添加信号
int sigaddset(sigset_t *set, int signo);
作用:
向指定信号集中添加一个信号。
例如:
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGQUIT);
现在信号集包含:
{ SIGINT, SIGQUIT }
6.4 sigdelset:从信号集中删除信号
int sigdelset(sigset_t *set, int signo);
作用:
从信号集中删除指定信号。
例如:
sigdelset(&set, SIGINT);
执行之后:
{ SIGQUIT }
6.5 sigismember:判断信号是否在信号集中
int sigismember(const sigset_t *set, int signo);
作用:
判断指定信号是否包含在信号集中。
返回值:
- 1:包含该信号;
- 0:不包含该信号;
- -1:调用出错。
例如:
if (sigismember(&set, SIGINT) == 1)
{
cout << "SIGINT 在信号集中" << endl;
}
6.6 函数总结
| sigemptyset | 清空信号集 |
| sigfillset | 填满信号集 |
| sigaddset | 添加信号 |
| sigdelset | 删除信号 |
| sigismember | 判断信号是否存在 |
这几个函数的返回值:
- 前四个函数:成功返回 0,失败返回 -1;
- sigismember():包含返回 1,不包含返回 0,出错返回 -1。
特别注意:使用 sigset_t 变量之前,一定要先调用 sigemptyset() 或 sigfillset() 初始化。
七、sigprocmask:修改进程的阻塞信号集
前面我们已经知道:
Block 记录哪些信号被阻塞。
那么问题来了:
我们应该如何修改 Block 呢?
Linux 提供了一个非常重要的函数:
#include <signal.h>
int sigprocmask(int how,
const sigset_t *set,
sigset_t *oldset);
它的作用是:
读取或修改当前进程的信号屏蔽字,也就是阻塞信号集。
7.1 参数介绍
参数一:how
表示应该如何修改当前的信号屏蔽字。
它有三种取值:
| SIG_BLOCK | 添加阻塞信号 | 把 set 中的信号加入屏蔽字 |
| SIG_UNBLOCK | 解除阻塞信号 | 把 set 中的信号从屏蔽字删除 |
| SIG_SETMASK | 替换整个屏蔽字 | 直接将屏蔽字设置为 set |
我们分别来看。
1. SIG_BLOCK:添加阻塞
sigprocmask(SIG_BLOCK, &set, nullptr);
表示:
把 set 中的信号加入当前进程的阻塞信号集。
例如:
原来的 Block:
{ SIGINT }
现在 set:
{ SIGQUIT }
执行之后:
{ SIGINT, SIGQUIT }
可以理解为:
Block = Block | set;
2. SIG_UNBLOCK:解除阻塞
sigprocmask(SIG_UNBLOCK, &set, nullptr);
表示:
解除 set 中信号的阻塞状态。
例如:
原来的 Block:
{ SIGINT, SIGQUIT }
现在 set:
{ SIGINT }
执行之后:
{ SIGQUIT }
可以理解为:
Block = Block & ~set;
3. SIG_SETMASK:直接替换
sigprocmask(SIG_SETMASK, &set, nullptr);
表示:
直接把当前进程的阻塞信号集替换为 set。
例如:
原来的 Block:
{ SIGINT, SIGQUIT }
现在 set:
{ SIGTERM }
执行之后:
{ SIGTERM }
可以理解为:
Block = set;
这三种操作一定要区分清楚:
- SIG_BLOCK:添加;
- SIG_UNBLOCK:删除;
- SIG_SETMASK:整体替换。
7.2 参数二:set
set 是一个输入参数。
它表示我们希望添加、解除或者设置哪些信号。
例如:
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigprocmask(SIG_BLOCK, &set, nullptr);
表示阻塞 SIGINT。
7.3 参数三:oldset
oldset 是一个输出参数。
如果它不是空指针,函数会把修改之前的信号屏蔽字保存到 oldset 中。
例如:
sigset_t set;
sigset_t oldset;
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigprocmask(SIG_BLOCK, &set, &oldset);
执行之后:
- 当前进程的 Block 增加了 SIGINT;
- oldset 保存修改之前的 Block。
这样做有什么用?
方便我们之后恢复原来的信号屏蔽字。
例如:
sigprocmask(SIG_SETMASK, &oldset, nullptr);
这就把当前信号屏蔽字恢复成之前保存的状态。
7.4 返回值
成功:0
失败:–1
还有一个非常重要的细节:
如果解除阻塞时,发现有对应的未决信号,那么这些信号可能会立即递达。
也就是说:
解除阻塞不只是修改 Block,还可能触发 Pending 中信号的递达。
八、sigpending:读取未决信号集
前面介绍了 sigprocmask(),它可以修改 Block。
那么,Pending 应该如何读取呢?
Linux 提供了:
#include <signal.h>
int sigpending(sigset_t *set);
作用:
读取当前进程的未决信号集,并通过 set 参数返回。
例如:
sigset_t pending;
sigpending(&pending);
执行之后,pending 中就保存了当前进程的未决信号信息。
我们可以结合前面学习的 sigismember() 判断某个信号是否处于未决状态:
if (sigismember(&pending, SIGINT))
{
cout << "SIGINT 处于未决状态" << endl;
}
返回值:
成功:0
失败:-1
注意: sigpending() 只能读取 Pending,不能直接修改 Pending。
用户程序不能直接把内核中的未决信号位图随意改成 1 或 0。
信号的产生和递达由内核管理。
九、动手实验:阻塞 SIGINT,观察 Pending 的变化
理论讲了这么多,现在我们通过一个实验,把前面学到的知识全部串起来。
9.1 实验目标
我们希望实现:
9.2 完整代码
#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <cstdio>
using namespace std;
// 打印当前进程的未决信号集
void PrintPending(const sigset_t &pending)
{
cout << "curr process[" << getpid() << "] pending: ";
// 这里打印 31~1 号标准信号的状态
for (int signo = 31; signo >= 1; —signo)
{
if (sigismember(&pending, signo))
{
cout << "1";
}
else
{
cout << "0";
}
}
cout << endl;
}
// SIGINT 的处理函数
void handler(int signo)
{
cout << signo << " 号信号被递达!" << endl;
}
int main()
{
// 1. 注册 SIGINT 的处理函数
signal(SIGINT, handler);
// 2. 创建阻塞信号集和旧信号屏蔽字
sigset_t block_set;
sigset_t old_set;
sigemptyset(&block_set);
sigemptyset(&old_set);
// 3. 将 SIGINT 添加到 block_set
sigaddset(&block_set, SIGINT);
// 4. 阻塞 SIGINT,并保存原来的信号屏蔽字
sigprocmask(SIG_BLOCK, &block_set, &old_set);
int cnt = 15;
while (true)
{
// 5. 获取当前进程的未决信号集
sigset_t pending;
sigpending(&pending);
// 6. 打印 Pending
PrintPending(pending);
—cnt;
// 7. 计数结束,恢复原来的信号屏蔽字
if (cnt == 0)
{
cout << "解除对 SIGINT 的阻塞!" << endl;
sigprocmask(SIG_SETMASK, &old_set, nullptr);
}
sleep(1);
}
return 0;
}
编译运行:

9.3 实验现象
程序刚运行时,Pending 中没有 SIGINT:

此时按下:
Ctrl + C
由于我们已经阻塞了 SIGINT,进程不会立即终止,而是继续运行。
Pending 中对应的位置变成了 1:

这说明:
SIGINT 已经产生,但是因为被阻塞,所以暂时处于未决状态。
等计数结束,程序执行:
sigprocmask(SIG_SETMASK, &old_set, nullptr);
恢复原来的信号屏蔽字。
如果原来的屏蔽字没有阻塞 SIGINT,那么之前处于 Pending 状态的 SIGINT 就可以递达。
于是执行:

如果使用默认处理动作,解除阻塞后进程则会按照 SIGINT 的默认动作终止。
9.4 为什么 Ctrl+\\ 仍然可以终止程序?
实验过程中,你可能会发现:
虽然 Ctrl+C 无法终止程序,但是 Ctrl+\\ 仍然可以终止程序。
这是为什么?
因为:
- Ctrl+C 产生 SIGINT,我们只阻塞了 SIGINT;
- Ctrl+\\ 产生 SIGQUIT,它没有被阻塞。
因此,SIGQUIT 仍然可以正常递达,并执行默认处理动作。
这也说明:
阻塞某个信号,并不意味着阻塞所有信号。
十、常规信号为什么会丢失?
现在我们再思考一个问题:
如果 SIGINT 已经被阻塞,那么我们连续按下十次 Ctrl+C,Pending 会记录十次吗?
答案是:
不会。
对于 Linux 的常规信号,如果某个信号在递达之前产生多次,通常只会记录一次。
例如:
#mermaid-svg-dDscV3OULumbebCX{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-dDscV3OULumbebCX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-dDscV3OULumbebCX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-dDscV3OULumbebCX .error-icon{fill:#552222;}#mermaid-svg-dDscV3OULumbebCX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dDscV3OULumbebCX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-dDscV3OULumbebCX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dDscV3OULumbebCX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dDscV3OULumbebCX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-dDscV3OULumbebCX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dDscV3OULumbebCX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dDscV3OULumbebCX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dDscV3OULumbebCX .marker.cross{stroke:#333333;}#mermaid-svg-dDscV3OULumbebCX svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dDscV3OULumbebCX p{margin:0;}#mermaid-svg-dDscV3OULumbebCX .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-dDscV3OULumbebCX .cluster-label text{fill:#333;}#mermaid-svg-dDscV3OULumbebCX .cluster-label span{color:#333;}#mermaid-svg-dDscV3OULumbebCX .cluster-label span p{background-color:transparent;}#mermaid-svg-dDscV3OULumbebCX .label text,#mermaid-svg-dDscV3OULumbebCX span{fill:#333;color:#333;}#mermaid-svg-dDscV3OULumbebCX .node rect,#mermaid-svg-dDscV3OULumbebCX .node circle,#mermaid-svg-dDscV3OULumbebCX .node ellipse,#mermaid-svg-dDscV3OULumbebCX .node polygon,#mermaid-svg-dDscV3OULumbebCX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-dDscV3OULumbebCX .rough-node .label text,#mermaid-svg-dDscV3OULumbebCX .node .label text,#mermaid-svg-dDscV3OULumbebCX .image-shape .label,#mermaid-svg-dDscV3OULumbebCX .icon-shape .label{text-anchor:middle;}#mermaid-svg-dDscV3OULumbebCX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-dDscV3OULumbebCX .rough-node .label,#mermaid-svg-dDscV3OULumbebCX .node .label,#mermaid-svg-dDscV3OULumbebCX .image-shape .label,#mermaid-svg-dDscV3OULumbebCX .icon-shape .label{text-align:center;}#mermaid-svg-dDscV3OULumbebCX .node.clickable{cursor:pointer;}#mermaid-svg-dDscV3OULumbebCX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-dDscV3OULumbebCX .arrowheadPath{fill:#333333;}#mermaid-svg-dDscV3OULumbebCX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-dDscV3OULumbebCX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-dDscV3OULumbebCX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dDscV3OULumbebCX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-dDscV3OULumbebCX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dDscV3OULumbebCX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-dDscV3OULumbebCX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-dDscV3OULumbebCX .cluster text{fill:#333;}#mermaid-svg-dDscV3OULumbebCX .cluster span{color:#333;}#mermaid-svg-dDscV3OULumbebCX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-dDscV3OULumbebCX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-dDscV3OULumbebCX rect.text{fill:none;stroke-width:0;}#mermaid-svg-dDscV3OULumbebCX .icon-shape,#mermaid-svg-dDscV3OULumbebCX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dDscV3OULumbebCX .icon-shape p,#mermaid-svg-dDscV3OULumbebCX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-dDscV3OULumbebCX .icon-shape .label rect,#mermaid-svg-dDscV3OULumbebCX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dDscV3OULumbebCX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-dDscV3OULumbebCX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-dDscV3OULumbebCX :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-dDscV3OULumbebCX .startNode>*{fill:#F8FAFC!important;stroke:#94A3B8!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-dDscV3OULumbebCX .startNode span{fill:#F8FAFC!important;stroke:#94A3B8!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-dDscV3OULumbebCX .startNode tspan{fill:#333!important;}#mermaid-svg-dDscV3OULumbebCX .statusNode>*{fill:#F3E8FF!important;stroke:#D8B4FE!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-dDscV3OULumbebCX .statusNode span{fill:#F3E8FF!important;stroke:#D8B4FE!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-dDscV3OULumbebCX .statusNode tspan{fill:#333!important;}
第 1 次
第 2 次
第 3 次
SIGINT 多次产生
Pending[2] = 1
Pending[2] 仍然是 1
Pending[2] 仍然是 1
为什么?
因为常规信号的未决状态采用位图记录。
一个 bit 只能表示两种状态:
0:没有处于未决状态
1:处于未决状态
它并不记录这个信号究竟产生了多少次。
因此,多个相同的常规信号在递达之前产生,通常会合并成一个。
10.1 实时信号可以排队
Linux 还提供了实时信号。
与常规信号不同,实时信号支持排队。
例如:
#mermaid-svg-50wE1Qgjhb2BGhdA{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-50wE1Qgjhb2BGhdA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-50wE1Qgjhb2BGhdA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-50wE1Qgjhb2BGhdA .error-icon{fill:#552222;}#mermaid-svg-50wE1Qgjhb2BGhdA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-50wE1Qgjhb2BGhdA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-50wE1Qgjhb2BGhdA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-50wE1Qgjhb2BGhdA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-50wE1Qgjhb2BGhdA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-50wE1Qgjhb2BGhdA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-50wE1Qgjhb2BGhdA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-50wE1Qgjhb2BGhdA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-50wE1Qgjhb2BGhdA .marker.cross{stroke:#333333;}#mermaid-svg-50wE1Qgjhb2BGhdA svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-50wE1Qgjhb2BGhdA p{margin:0;}#mermaid-svg-50wE1Qgjhb2BGhdA .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-50wE1Qgjhb2BGhdA .cluster-label text{fill:#333;}#mermaid-svg-50wE1Qgjhb2BGhdA .cluster-label span{color:#333;}#mermaid-svg-50wE1Qgjhb2BGhdA .cluster-label span p{background-color:transparent;}#mermaid-svg-50wE1Qgjhb2BGhdA .label text,#mermaid-svg-50wE1Qgjhb2BGhdA span{fill:#333;color:#333;}#mermaid-svg-50wE1Qgjhb2BGhdA .node rect,#mermaid-svg-50wE1Qgjhb2BGhdA .node circle,#mermaid-svg-50wE1Qgjhb2BGhdA .node ellipse,#mermaid-svg-50wE1Qgjhb2BGhdA .node polygon,#mermaid-svg-50wE1Qgjhb2BGhdA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-50wE1Qgjhb2BGhdA .rough-node .label text,#mermaid-svg-50wE1Qgjhb2BGhdA .node .label text,#mermaid-svg-50wE1Qgjhb2BGhdA .image-shape .label,#mermaid-svg-50wE1Qgjhb2BGhdA .icon-shape .label{text-anchor:middle;}#mermaid-svg-50wE1Qgjhb2BGhdA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-50wE1Qgjhb2BGhdA .rough-node .label,#mermaid-svg-50wE1Qgjhb2BGhdA .node .label,#mermaid-svg-50wE1Qgjhb2BGhdA .image-shape .label,#mermaid-svg-50wE1Qgjhb2BGhdA .icon-shape .label{text-align:center;}#mermaid-svg-50wE1Qgjhb2BGhdA .node.clickable{cursor:pointer;}#mermaid-svg-50wE1Qgjhb2BGhdA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-50wE1Qgjhb2BGhdA .arrowheadPath{fill:#333333;}#mermaid-svg-50wE1Qgjhb2BGhdA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-50wE1Qgjhb2BGhdA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-50wE1Qgjhb2BGhdA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-50wE1Qgjhb2BGhdA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-50wE1Qgjhb2BGhdA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-50wE1Qgjhb2BGhdA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-50wE1Qgjhb2BGhdA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-50wE1Qgjhb2BGhdA .cluster text{fill:#333;}#mermaid-svg-50wE1Qgjhb2BGhdA .cluster span{color:#333;}#mermaid-svg-50wE1Qgjhb2BGhdA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-50wE1Qgjhb2BGhdA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-50wE1Qgjhb2BGhdA rect.text{fill:none;stroke-width:0;}#mermaid-svg-50wE1Qgjhb2BGhdA .icon-shape,#mermaid-svg-50wE1Qgjhb2BGhdA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-50wE1Qgjhb2BGhdA .icon-shape p,#mermaid-svg-50wE1Qgjhb2BGhdA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-50wE1Qgjhb2BGhdA .icon-shape .label rect,#mermaid-svg-50wE1Qgjhb2BGhdA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-50wE1Qgjhb2BGhdA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-50wE1Qgjhb2BGhdA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-50wE1Qgjhb2BGhdA :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-50wE1Qgjhb2BGhdA .actionNode>*{fill:#E0F2FE!important;stroke:#7DD3FC!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-50wE1Qgjhb2BGhdA .actionNode span{fill:#E0F2FE!important;stroke:#7DD3FC!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-50wE1Qgjhb2BGhdA .actionNode tspan{fill:#333!important;}#mermaid-svg-50wE1Qgjhb2BGhdA .queueNode>*{fill:#FFE4E6!important;stroke:#FDA4AF!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-50wE1Qgjhb2BGhdA .queueNode span{fill:#FFE4E6!important;stroke:#FDA4AF!important;stroke-width:2px!important;color:#333!important;rx:6!important;ry:6!important;}#mermaid-svg-50wE1Qgjhb2BGhdA .queueNode tspan{fill:#333!important;}
实时信号产生第 1 次
进入队列 (节点 1)
实时信号产生第 2 次
进入队列 (节点 2)
实时信号产生第 3 次
进入队列 (节点 3)
等到可以递达时,再按照队列顺序处理。
因此:
| 常规信号 | 通常合并,不保证逐次递达 |
| 实时信号 | 支持排队,可以逐次递达 |
十一、Core Dump:进程异常终止时留下的调试信息
在上一篇中,我们已经介绍过 Core Dump。
这里再结合信号递达机制简单回顾一下。
当某些信号递达时,如果它们的默认处理动作是 Core,进程异常终止时就可能生成 core 文件。
例如:
- SIGQUIT
- SIGFPE
- SIGSEGV
Core Dump 可以理解为:
进程异常终止时,将用于调试的进程状态信息保存到文件中,方便开发者事后排查问题。
11.1 为什么没有生成 core 文件?
可以先查看:
ulimit -a
其中:
core file size (blocks, -c) 0
表示当前 shell 对应的 core 文件大小限制为 0。
也就是说,默认不允许生成 core 文件。
可以使用:
ulimit -c unlimited
允许生成不受该大小限制约束的 core 文件。
11.2 使用 GDB 调试 core 文件
如果程序发生异常并生成了 core 文件,可以使用:
gdb ./testsig core
进入 GDB 后:
bt
查看函数调用栈,帮助定位程序异常的位置。
11.3 waitpid 如何判断是否产生 Core?
父进程可以通过 waitpid() 获取子进程的退出状态。
判断时不要自己手动拆位,直接使用系统提供的宏:
| WIFEXITED(status) | 判断是否正常退出 |
| WEXITSTATUS(status) | 获取正常退出时的退出码 |
| WIFSIGNALED(status) | 判断是否被信号终止 |
| WTERMSIG(status) | 获取导致终止的信号编号 |
| WCOREDUMP(status) | 判断是否产生了 core dump |
其中,WCOREDUMP() 是 Linux 等系统提供的扩展接口,使用时需要注意平台兼容性。
记住:
waitpid() 返回的 status 是编码后的状态信息,不是简单的退出码。
十二、本篇总结
学到这里,我们已经把 Linux 信号的保存机制串起来了。
12.1 三个核心信息
| Block | 阻塞信号集 | 哪些信号被阻塞 |
| Pending | 未决信号集 | 哪些信号已经产生但尚未递达 |
| Handler | 处理动作 | 信号递达时应该执行什么动作 |
12.2 常用函数
| sigemptyset | 初始化为空信号集 |
| sigfillset | 初始化为包含系统支持信号的信号集 |
| sigaddset | 添加信号 |
| sigdelset | 删除信号 |
| sigismember | 判断信号是否存在 |
| sigprocmask | 读取或修改信号屏蔽字 |
| sigpending | 读取未决信号集 |
12.3 信号产生到递达的完整流程

12.4 面试易错点
| 未决和阻塞是一回事吗? | 不是。Pending 表示信号已经产生但尚未递达,Block 表示信号是否被阻塞 |
| 阻塞和忽略一样吗? | 不一样。阻塞发生在递达之前,忽略是递达时的处理动作 |
| sigprocmask 修改哪个集合? | 修改 Block,也就是信号屏蔽字 |
| sigpending 修改哪个集合? | 它只能读取 Pending,不能直接修改 |
| sigemptyset 有什么作用? | 初始化一个空信号集 |
| SIG_BLOCK 和 SIG_SETMASK 有什么区别? | 前者添加阻塞信号,后者整体替换屏蔽字 |
| 常规信号会排队吗? | Linux 中常规信号在递达前多次产生通常只记录一次 |
| 实时信号会排队吗? | 支持排队 |
| 解除阻塞后会发生什么? | 对应的未决信号可能立即递达 |
| SIGKILL 可以被阻塞吗? | 不可以 |
结语:
今天的内容到这里就结束了,希望你能有所收获~
干货整理到手抖,觉得有用的话,赏个三连回回血?__(:ᗤ」ㄥ)_ _


