可通过cat /proc/[pid]/status | grep SigBlk查看进程信号屏蔽字,SigBlk字段为十六进制64位掩码(低32位有效),每位为1表示对应编号信号被屏蔽,如0000000000000004二进制为100,第3位为1,即屏蔽SIGQUIT(编号3)。

怎么查进程当前屏蔽了哪些信号
没有直接命令能实时 dump 某个运行中进程的 block 位图(即信号屏蔽字),因为内核不提供该信息的用户态导出接口。但你可以通过 /proc/[pid]/status 中的 SigBlk 字段间接查看 —— 它是十六进制格式的 64 位掩码(实际只用低 32 位),每位对应一个信号是否被阻塞。
操作步骤:
- 运行
cat /proc/1234/status | grep SigBlk(把1234换成目标 PID) - 拿到类似
SigBlk: 0000000000000004的值,转成二进制后,从右往左数第n位为 1,表示信号n被屏蔽(注意:第 0 位不用,第 1 位对应SIGHUP,第 2 位对应SIGINT) - 例如
0000000000000004十六进制 =100二进制 → 第 3 位为 1 → 屏蔽的是SIGQUIT(编号 3)
如何验证 SIGINT 是否真的被屏蔽了
光看 SigBlk 不够直观,得结合行为验证。关键点是:屏蔽 ≠ 忽略,被屏蔽的信号会进入 pending 状态,解除屏蔽后立刻递达。
实操建议:
- 写一个简单程序,在关键段调用
sigprocmask(SIG_BLOCK, &set, NULL)屏蔽SIGINT,然后sleep(10) - 在 sleep 期间按
Ctrl+C(发送SIGINT),进程不会退出 - 紧接着调用
sigpending(&set)打印未决信号集,会看到SIGINT在其中 - 再调用
sigprocmask(SIG_UNBLOCK, &set, NULL),进程立刻响应并退出
如果没看到 pending,说明屏蔽没生效 —— 常见原因是没正确初始化 sigset_t(漏掉 sigemptyset() 或 sigfillset())
调试时怎么知道信号卡在哪一步
信号处理链路有三处可能“卡住”:没产生、被屏蔽、没注册 handler。逐层排查比猜更快。
检查顺序和工具:
- 用
kill -l确认信号编号和名字对得上(比如SIGUSR1是 10,不是 1) - 用
strace -p [pid] -e trace=signal观察内核是否把信号真正递送给进程(若没输出,说明信号根本没发到进程) - 用
cat /proc/[pid]/status | grep -E "SigPnd|SigBlk|SigCgt"分别看 pending、blocked、caught 位图,确认信号是否挂起、是否被屏蔽、是否注册了 handler -
SigCgt值非零,说明对应信号设置了自定义 handler;若为 0 且没忽略,则走默认动作
特别注意:SIGKILL 和 SIGSTOP 永远无法被屏蔽或捕捉,调试时别在这俩上浪费时间
为什么 sigpending() 总返回空?
常见误解是“只要发了信号,sigpending() 就该看到”,其实它只报告「已到达但被屏蔽」的信号。如果信号没被屏蔽,它会立刻递达(执行 handler 或默认动作),不会进 pending 集合。
典型错误场景:
- 调用
sigpending()前没先屏蔽目标信号(比如忘了sigprocmask(SIG_BLOCK, &set, NULL)) - 信号在调用
sigpending()之前已被递达(比如 handler 已执行完) - 用
signal()注册 handler 后又没重新屏蔽 ——signal()在某些系统上会自动重置屏蔽字,导致刚屏蔽的信号又被解除了 - 多线程环境下用了
sigprocmask()(进程级)而非pthread_sigmask()(线程级),结果只影响主线程
最稳妥的验证方式:屏蔽信号 → 发送信号 → 立即调用 sigpending() → 解除屏蔽 → 观察 handler 是否触发。中间任何一环断开,sigpending() 都看不到东西











