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

C语言sigprocmask阻塞信号解除后第二部分代码不执行问题

问题原因分析
  • 标准信号(SIGINT、SIGQUIT都属于此类)在Linux系统下不支持排队,阻塞期间多次触发的同一信号,内核只会保留1个待处理(pending)标记。
  • 第一个循环运行时按下的Ctrl+C、Ctrl+\产生的信号会进入pending队列,当调用sigprocmask(SIG_UNBLOCK, &sigs, NULL)解除阻塞的瞬间,内核会立即将这些pending信号递送给进程。
  • SIGINT和SIGQUIT的默认处理动作都是终止进程,因此进程会在解除阻塞的瞬间直接退出,不会执行后续的第二个for循环代码。
解决方案

要实现阻塞期间触发的信号被丢弃、仅解除阻塞后新触发的信号才能终止进程的效果,需要在解除阻塞前先清空阻塞期间累积的pending信号,修改后的代码如下:

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

int main()
{
    int i;
    sigset_t sigs, pending;

    sigemptyset(&sigs);
    sigaddset(&sigs, SIGINT);
    sigaddset(&sigs, SIGQUIT);

    sigprocmask(SIG_SETMASK, &sigs, NULL);

    for (i=0; i<5; ++i)
    {
        printf("(block) working ....\n");
        sleep (1); 
    }
    printf("The work is done, now you can ...\n");

    // 先获取当前pending的信号集
    sigpending(&pending);
    if (sigismember(&pending, SIGINT) || sigismember(&pending, SIGQUIT)) {
        // 临时将信号处理设置为忽略,丢弃之前阻塞的信号
        signal(SIGINT, SIG_IGN);
        signal(SIGQUIT, SIG_IGN);
        sigprocmask(SIG_UNBLOCK, &sigs, NULL);
        // 恢复信号的默认处理动作,后续新触发的信号可正常终止进程
        signal(SIGINT, SIG_DFL);
        signal(SIGQUIT, SIG_DFL);
    } else {
        // 无pending信号直接解除阻塞
        sigprocmask(SIG_UNBLOCK, &sigs, NULL);
    }

    for (int j=0; j<5; ++j)
    {
        printf("(unblock) working ....\n");
        sleep (1); 
    }
    exit(0);
}

修改后运行效果完全符合预期:第一个循环期间按下的快捷键信号会被直接丢弃,第二个循环运行时按下对应快捷键会触发默认动作终止程序。

内容的提问来源于stack exchange,提问作者j.hall

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 14:03:00