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

Ubuntu22.04下C++进程中raise()优先触发默认信号处理器而非sigwait()的疑问

问题:raise()与kill(getpid())在sigwait()场景下的行为差异

我在Ubuntu-22.04上运行一个C++进程,主线程通过sigwait()阻塞,直到收到SIG_INT或SIG_TERM信号后退出。外部用kill -INT <pid>发送信号时,sigwait()能正常解除阻塞,主线程顺利退出;但在进程内部调用raise(SIG_INT)时,sigwait()仍处于阻塞状态,信号会被默认处理器处理(未安装自定义处理器)。原本预期raise()和外部kill命令效果一致,但实际不符。换成kill(getpid(), signal)就能达到预期(sigwait()解除阻塞),想知道两者行为差异的原因。

以下是使用sigwait()的等待实现:

int wait_stop_signals()
{
    sigset_t sigset;
    sigemptyset(&sigset);
    // 添加要阻塞并等待的终止信号
    sigaddset(&sigset, SIGINT);
    sigaddset(&sigset, SIGTERM);

    // 阻塞要等待的信号,避免触发默认处理器
    int rc = pthread_sigmask(SIG_BLOCK, &sigset, nullptr);
    if (rc != 0) {
        return rc;
    }

    int sig = 0;
    // 阻塞直到等待的信号到达
    return sigwait(&sigset, &sig);
}

行为差异的核心原因

1. raise()的信号投递逻辑

raise(sig)本质等价于pthread_kill(pthread_self(), sig),它是向当前调用线程定向发送信号。由于主线程已经通过pthread_sigmask阻塞了SIG_INT/SIG_TERM,调用raise()后,信号会被标记为当前线程的「待处理(pending)」状态,但因为线程本身阻塞了该信号,这个pending信号不会被sigwait()捕获——sigwait()优先处理的是进程级的pending信号,而非当前线程的pending信号。最终这个无法被处理的信号会触发默认处理器。

2. kill(getpid(), sig)的信号投递逻辑

kill(getpid(), sig)是向整个进程发送信号,信号会被标记为进程级的pending状态。sigwait()的设计就是监听这类进程级pending信号:当检测到目标信号处于pending且被阻塞时,就会捕获该信号并解除阻塞,这就和外部用kill命令发送信号的行为一致了。

简单总结:raise()是线程定向的信号,而kill(getpid())是进程定向的信号,sigwait()只识别进程级的pending信号,这就是两者行为差异的根源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 23:31:15