Linux进程信号详解:从产生、保存到捕捉的完整排查记录

发布时间:2026/9/29 22:11:09

Linux进程信号详解:从产生、保存到捕捉的完整排查记录 上周线上一个后台采集进程半夜挂了日志最后一行是空的没有堆栈没有 core。运维说机器没重启OOM 也没记录。我第一反应是收到了某个默认动作是终止的信号比如 SIGTERM 或 SIGPIPE。这篇就把排查过程和我重新梳理的信号知识记下来。问题复现进程是个常驻的 C 程序往一个管道写数据。简化后大概这样#includestdio.h#includeunistd.hintmain(void){intfd[2];pipe(fd);close(fd[0]);// 故意关掉读端for(;;){// 写端还在但读端已关闭ssize_tnwrite(fd[1],hello,5);printf(write %zd\n,n);sleep(1);}return0;}编译运行gcc-odemo demo.c ./demo结果进程直接消失连printf都没打出来。用echo $?看退出码是 141也就是 1281313 正是 SIGPIPE。信号这东西平时写业务代码感觉不到一旦出事就是这种静默死亡。排查过程线上没法复现我先在本地用 strace 跟一下看进程到底是怎么死的strace-f-etracewrite,rt_sigaction ./demo输出里能看到write返回-1 EPIPE紧接着是--- SIGPIPE {si_signoSIGPIPE, si_codeSI_USER, ...} ---然后 killed by SIGPIPE 。这一步确认了信号是内核对写已关闭管道这个动作的直接响应不是别的进程发的。接着我想确认进程当前对哪些信号做了处理。看/proccat/proc/pid/status|grep-isig几个关键字段字段含义SigPnd线程组共享的 pending 信号位图ShdPnd进程级 pending老内核用 SigPnd 表示SigBlk被阻塞blocked的信号掩码SigIgn被忽略的信号掩码SigCgt被捕捉caught即注册了 handler的信号掩码这些是 64 位十六进制每一位对应一个信号。比如 SigCgt 是0000000000000002第 2 位从 1 数为 1说明 SIGINT 被捕捉了。我当初就是靠 SigCgt 确认进程根本没给 SIGPIPE 注册 handler所以走了默认动作——终止。根因要讲清楚得把信号的生命周期拆成三段产生 → 保存 → 捕捉/递送。一、信号怎么产生常见来源有四类终端按键CtrlC 发 SIGINTCtrl\ 发 SIGQUITCtrlZ 发 SIGTSTP。硬件异常除零发 SIGFPE非法内存访问发 SIGSEGV这些由内核在异常处理里转成信号。kill / raise / abortkill(pid, sig)给指定进程raise(sig)给自己abort()发 SIGABRT。软件条件管道读端关闭后写数据触发 SIGPIPE定时器到期触发 SIGALRM子进程退出触发 SIGCHLD。我这次就是第 4 类。二、信号怎么保存信号不是立刻执行的。内核对每个进程维护两张位图pending未决位图信号产生了但还没被递送就挂在这里。blocked阻塞位图被阻塞的信号即使产生也只能待在 pending不会递送。只有pending 且未 blocked的信号才会被递送。这两张位图都是 64 位sigset_t普通信号 1~31实时信号 32~64。这里有个关键差异很多人踩过类型范围多次产生同一信号是否排队不可靠信号标准信号1~31只保留一个 pending 位不排队可靠信号实时信号32~64内核维护队列排队按序递送也就是说给一个阻塞了 SIGUSR1 的进程连发 10 次 SIGUSR1解除阻塞后它只处理 1 次。换成 SIGRTMIN 就会处理 10 次。这一点我用下面的代码验证过。三、信号怎么捕捉捕捉就是注册 handler。老接口是signal()新接口是sigaction()。生产代码应该用sigaction因为signal在不同 Unix 上语义不一致而且拿不到siginfo_t。sigaction里几个要点sa_handler和sa_sigaction是联合体二选一。想拿详细信息谁发的、什么原因要设SA_SIGINFO用三参数版本。sa_mask是 handler 执行期间额外要阻塞的信号集当前信号默认会被自动阻塞除非设了SA_NODEFER。SA_RESTART让被信号打断的系统调用自动重启不设的话read/write可能返回EINTR。还有一点必须强调handler 里能调用的函数是有限的。只有异步信号安全async-signal-safe的函数才安全比如write、_exit、sig_atomic_t的读写。printf、malloc、free都不安全因为可能重入锁。我见过在 handler 里printf然后死锁的案例。正确做法是往一个volatile sig_atomic_t变量写标志主循环去轮询。解决方案回到我的问题SIGPIPE 有两种处理方式全局忽略signal(SIGPIPE, SIG_IGN)之后write会返回 -1 并置errno EPIPE由代码自己处理。用send的MSG_NOSIGNAL标志仅 socket。对管道场景只能选方案 1。我改成注册一个 handler 记录日志同时把 SIGPIPE 加入阻塞集避免在主逻辑中途被打断。下面是我最终用的骨架代码涵盖注册、阻塞、pending 读取#define_GNU_SOURCE#includestdio.h#includestdlib.h#includestring.h#includeunistd.h#includesignal.h#includeerrno.hstaticvolatilesig_atomic_tg_got_sigpipe0;staticvoidon_sigpipe(intsig,siginfo_t*info,void*ucontext){(void)ucontext;// 只做异步信号安全的事g_got_sigpipesig;// 想记日志用 write不要 printfconstcharmsg[]caught SIGPIPE\n;write(STDERR_FILENO,msg,sizeof(msg)-1);(void)info;}intmain(void){structsigactionsa;memset(sa,0,sizeof(sa));sa.sa_sigactionon_sigpipe;sa.sa_flagsSA_SIGINFO|SA_RESTART;sigemptyset(sa.sa_mask);sigaddset(sa.sa_mask,SIGINT);// handler 期间顺便屏蔽 SIGINTif(sigaction(SIGPIPE,sa,NULL)-1){perror(sigaction);return1;}// 演示阻塞 SIGUSR1观察 pendingsigset_tblock,old;sigemptyset(block);sigaddset(block,SIGUSR1);sigprocmask(SIG_BLOCK,block,old);raise(SIGUSR1);raise(SIGUSR1);raise(SIGUSR1);sigset_tpend;sigpending(pend);if(sigismember(pend,SIGUSR1))write(STDOUT_FILENO,SIGUSR1 pending\n,16);// 解除阻塞只会递送一次sigprocmask(SIG_SETMASK,old,NULL);intfd[2];pipe(fd);close(fd[0]);for(inti0;i3;i){ssize_tnwrite(fd[1],x,1);if(n-1errnoEPIPE)write(STDOUT_FILENO,EPIPE handled\n,14);sleep(1);}return0;}编译gcc-Wall-O2-osigdemo sigdemo.c验证结果跑一下./sigdemo输出稳定是SIGUSR1 pending caught SIGPIPE EPIPE handled caught SIGPIPE EPIPE handled caught SIGPIPE EPIPE handled几个观察连发 3 次 SIGUSR1只打印一次 pending解除阻塞后只递送一次。这验证了标准信号不排队。SIGPIPE 每次都被 handler 捕获write返回 -1 且errno EPIPE进程不再被杀。再确认一下/proc里 SigCgt 的变化进程运行期间grepSigCgt /proc/$(pgrep sigdemo)/status可以看到第 13 位SIGPIPE被置 1 了。补充几个我没验证的点避免误导实时信号的具体排队深度上限跟/proc/sys/kernel/rtsig-max有关但这个文件在新内核里已经被移除了具体行为我没有实测。SA_RESTART对哪些系统调用生效不同架构和内核版本有差异写代码时最好显式处理EINTR。小结信号的核心就三张东西pending 位图、blocked 位图、handler 表。产生只是置 pending 位递送的前提是没被 block 且默认动作不是忽略。标准信号不排队、handler 里只能用异步信号安全函数这两条是最容易翻车的。遇到进程静默死亡先看退出码是不是 128N再用 strace 抓信号基本能定位。
延伸阅读

更多相关文章

2026/9/29 22:11:09

Agent Skills实战指南:从安装到编写,解锁AI编程超级能力

最近圈子里聊AI编程,三句话不离skills。我刚开始以为又是营销号在造概念,直到自己动手把GitHub上的skills装进Claude Code,又照着社区规范写了一个用于数学建模论文排版的技能包之后,才明白为什么大家都说这是AI编程的“超级能力”…

2026/9/29 22:11:09

黄金偏弱待回踩4100

上周:黄金遇阻回落收跌,未能延续前周触底回升之势进一步反弹,再度跌至60周均线下方,空头占据优势,暗示后市走势仍偏弱。本周周一:黄金开盘低开低走,因受制于高企的美债收益率及美联储鹰派加息前…

2026/9/29 22:11:09

2026 Java 后端面试八股文全套汇总|纯干货,逐题详解

就目前大环境来看,跳槽成功的难度比往年高很多。一个明显的感受:今年的面试,无论一面还是二面,都很考验Java程序员的技术功底。这不马上又到了面试跳槽的黄金段,成功升职加薪,不成功饱受打击。当然也要注意…

2026/9/30 3:51:37

Model-Optimizer:大模型推理全链路分层优化实践指南

1. 项目概述:Model-Optimizer不是工具名,而是一类工程实践的统称 “Model-Optimizer”这个词在当前技术社区里常被误认为是一个具体软件或开源项目——比如有人搜“Model-Optimizer下载”“Model-Optimizer GitHub”,结果却找不到官方仓库。…

2026/9/30 3:51:37

SFINAE 机制全解析:从 enable_if 到 void_t 的模板实战

有些话说在前头:模板编程里最让人上头的部分,多半不是怎么把类型算出来,而是怎么让编译器“在你不想要的时候别报错,在你想选的时候刚好选对”。SFINAE 就是这一整套把戏的核心发动机。如果你玩 C 模板玩到一定阶段,一…

2026/9/30 3:51:37

大模型推理加速工程实践:TensorRT与vLLM协同部署指南

1. 项目概述:Model-Optimizer不是工具名,而是工程范式的代号“Model-Optimizer”这个标题乍看像某个开源库或GUI软件的名称,但结合NVIDIA、TensorRT-LLM、vLLM、PT文件转换、Docker镜像部署等高频热词,它实际指向的是一整套面向生…

2026/9/30 3:51:37

TensorFlow 2024实战:安装避坑、Keras 3与模型部署全流程

2024年聊起TensorFlow,注定不是一句"PyTorch已经赢了"能概括的。过去一年我在好几个生产项目里来回切换框架,发现一个特别有意思的错位:社交媒体上讨论最多的永远是PyTorch生态、LoRA微调、扩散模型,可当我拉开服务器上…

2026/9/30 3:51:37

自动化脚本实战指南:从Shell到UI、接口与CI部署

这些搜索词扔给我的一瞬间,我基本就明白了——问“自动化与脚本”的人,十个里有八个不是想听理论,而是正被某个具体的活儿追着跑:要么是测试任务重复到吐,要么是部署流程卡得人想骂人,再要么就是成天在不同…

2026/9/30 3:46:37

模型优化实战:从ONNX到TensorRT的量化、剪枝与部署加速指南

算力需求暴涨、落地 deadline 卡得死死的——“模型是训出来了,但根本跑不动”这种话我这两年听了太多。模型结构和训练效果只是第一步,真正考验工程能力的,是把一个训练好的模型安全、高效、低损耗地塞进生产环境。就在这个环节,…

2026/9/29 11:07:23

东莞市品牌网站建设报价常见报错与解决

东莞品牌网站建设报价单背后:一份保姆级建站教程避坑实录 网站做好了没人访问,这大概是很多老板最头疼的事。花了大几万做的品牌站,上线后流量惨淡,比路边摊还冷清。别急着骂外包公司,很多“东莞品牌网站建设报价”里藏着不少猫腻,比如用模板站冒充定制…

2026/9/29 21:48:03

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/29 7:00:49

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/30 0:01:22

MATLAB+Yalmip+CPLEX实战:综合能源系统优化调度全流程解析

做综合能源系统优化调度这活儿,最痛苦的不是建模本身,而是模型写完之后不知道该怎么求解。看论文里轻飘飘一句“采用Yalmip调用CPLEX求解”,自己上手时却往往卡在环境配置、变量声明、约束写法和求解状态判读上,一耗就是两三天。这…

2026/9/30 0:01:22

I3C比I2C快10倍?RK3576实战:速率、DTS配置与混合总线避坑指南

I3C 比 I2C 快 10 倍?这句话在嵌入式群里传了很久,每次都能吵出一堆截图。前段时间我正好在 RK3576 上调板级 I3C 接口,从控制器寄存器一路摸到 Linux DTS 配置,踩了不少坑,也把这笔速度账彻底算明白了。本文就用 RK35…

2026/9/30 0:01:22

字符串转对象:JSON.parse、new Function与URLSearchParams

“字符串转对象”这几个字,我在技术群里见过的问法至少有十几种:有人拿着一串{a:1,b:2}说 JSON.parse 直接报错,有人要从 URL 里抠出参数,还有人只是想把abc变成能挂属性的东西。js 这门语言里,字符串和对象之间的转换…

2026/9/29 3:53:39

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/29 9:46:12

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/29 6:36:14

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑