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

Linux下longjmp跳出信号处理器仅生效一次的问题解决问询

问题原因与解决方案

问题根源

Linux 系统中,当信号处理函数执行时,内核会自动屏蔽当前触发的信号(此处为 SIGINT)。你代码中使用的普通 setjmp()/longjmp() 不会恢复被屏蔽的信号掩码,导致第一次处理完 SIGINT 后,该信号始终处于屏蔽状态,后续 Ctrl+C 发送的 SIGINT 无法被程序接收,因此没有响应。

而 macOS 下的 longjmp() 行为不同,会自动恢复信号掩码,所以能正常重复响应 SIGINT。

修改后的代码

将普通跳转函数替换为支持信号掩码保存/恢复的 sigsetjmp() 和 siglongjmp(),即可解决问题:

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

static sigjmp_buf label;

static void handler(int type)
{
    printf("handler(%d)\n", type);
    signal(SIGINT, handler); // 重新注册信号处理函数
    siglongjmp(label, 1);
}

int main(int argc, char *argv[])
{
    signal(SIGINT, handler);
    if (sigsetjmp(label, 1)) // 第二个参数设为1,表示保存当前信号掩码
        printf("re-run\n");
    printf("running\n");
    sleep(1000);
    printf("done\n");
    return 0;
}

关键说明

  • sigsetjmp(label, 1):第二个参数为1时,会将当前的信号掩码保存到 sigjmp_buf 结构体中。
  • siglongjmp(label, 1):跳转时会自动恢复之前保存的信号掩码,SIGINT 不再被屏蔽,后续信号可以正常触发处理函数。

另外,更推荐使用 sigaction() 替代 signal() 设置信号处理函数,sigaction 行为更稳定且跨平台一致,优化后的代码如下:

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

static sigjmp_buf label;

static void handler(int type)
{
    printf("handler(%d)\n", type);
    siglongjmp(label, 1);
}

int main(int argc, char *argv[])
{
    struct sigaction sa;
    sa.sa_handler = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0; // 不设置SA_RESTART,避免sleep被信号中断后自动重启
    sigaction(SIGINT, &sa, NULL);

    if (sigsetjmp(label, 1))
        printf("re-run\n");
    printf("running\n");
    sleep(1000);
    printf("done\n");
    return 0;
}

使用 sigaction 无需手动重新注册信号处理函数(除非设置 SA_RESETHAND 标志),行为更可靠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 22:48:19