You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何向阻塞SIGUSR2的进程发信号后/proc/<pid>/status中SigPnd无变化?

阻塞信号未在SigPnd中显示挂起的原因解析

测试代码(test.c)

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void handler(int signum) {
    printf("\nGoodbye!\n"); exit(0);
}

int main() {
    struct sigaction sa = { .sa_handler = handler };

    // Intercept SIGINT
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGINT, &sa, NULL) == -1) {
        perror("sigaction"); exit(EXIT_FAILURE);
    }

    signal(SIGUSR1, SIG_IGN); // Ignore SIGUSR1

    // Block SIGUSR2
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGUSR2);
    sigprocmask(SIG_BLOCK, &mask, NULL);

    // Simulate work for 10 seconds
    for (int i = 0; i < 10; i++) {
        printf("Working... %d\n", i);
        sleep(1);
    } 
    sigprocmask(SIG_UNBLOCK, &mask, NULL);
}

操作步骤

  • 编译并运行上述程序
  • 程序运行期间执行信号发送命令:kill -s USR2 $(pgrep test)
  • 立即查看进程状态:cat /proc/$(pgrep test)/status | grep Sig

进程状态输出

SigQ:   1/256970
SigPnd: 0000000000000000
SigBlk: 0000000000000800
SigIgn: 0000000000000200
SigCgt: 0000000000000002

疑问

按照信号机制的逻辑,发送给进程的被阻塞信号应该处于挂起状态,直到解除阻塞,但这里SigPnd显示为0,没有任何挂起信号,这是为什么?

解答

问题出在你查看的字段范围和Linux信号挂起的存储逻辑:

  1. 字段匹配不全:你用grep Sig过滤状态时,漏掉了ShdPnd(线程组共享未决信号集)字段——这个字段的前缀是Shd而非Sig,所以没被匹配出来。
  2. 信号挂起的存储规则:当你向进程发送SIGUSR2时,由于进程内所有线程(这里是单线程的主线程)都阻塞了该信号,内核无法找到可递送信号的线程,因此会将这个信号挂起在**线程组共享的未决信号集(ShdPnd)**中,而非线程自身的SigPnd。

你可以执行以下命令查看完整的未决信号状态:

cat /proc/$(pgrep test)/status | grep -E 'SigPnd|ShdPnd'

此时会看到ShdPnd的值为0000000000000800,正好对应SIGUSR2的信号位(SIGUSR2是第12号信号,对应位为2^(12-1)=2048=0x800),证明信号确实处于挂起状态。

另外,SigQ中的第一个数值1也已经明确提示有1个未决信号,和你发送的SIGUSR2完全对应。当程序执行到sigprocmask(SIG_UNBLOCK)解除SIGUSR2的阻塞后,内核会将共享未决队列中的SIGUSR2递送给主线程,触发默认的进程终止动作。

内容的提问来源于stack exchange,提问作者nowox

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 23:17:31