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

如何确保每次按下Ctrl+C时,结合longjmp的SIGINT信号处理器均被触发?

问题根源分析

问题出在**longjmp()直接跳过了信号处理函数的正常返回流程,导致内核没有解除对SIGINT信号的阻塞**。

当信号触发时,内核会自动将当前信号(此处为SIGINT)加入进程的信号掩码,防止递归触发信号。如果信号处理函数正常返回,内核会自动移除该掩码;但你用longjmp()直接跳回主函数,信号处理函数未正常退出,内核也就不会解除对SIGINT的阻塞,后续的SIGINT信号都会被系统屏蔽。


两种解决方案

方案1:手动解除信号阻塞(基础版)

在longjmp()执行前,调用sigprocmask()手动解除对SIGINT的阻塞:

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

jmp_buf sjbuf;
void onintr(int);

void 
onintr(int i) 
{
    signal(SIGINT, onintr);
    printf("\nInterrupt(%d)\n", i);
    
    // 解除SIGINT的阻塞状态
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGINT);
    sigprocmask(SIG_UNBLOCK, &mask, NULL);
    
    longjmp(sjbuf, 0);
}

int 
main(int argc, char* argv[]) 
{
    int sleep_t = 1; 
    int ctr     = 0; 
    int timeout = 10;

    if (signal(SIGINT, SIG_IGN) != SIG_IGN)
        signal(SIGINT, onintr);

    setjmp(sjbuf);
    printf("Starting loop...\n");

    while (ctr < timeout) {
        printf("Going to sleep for %d second(s)\n", sleep_t);
        ctr++;
        sleep(sleep_t);
    }

    printf("\n");
    return 0;
}

方案2:使用信号专用跳转函数(推荐)

sigsetjmp()和siglongjmp()是标准库为信号场景设计的跳转函数,会自动保存和恢复进程的信号掩码,无需手动处理阻塞逻辑:

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

// 替换jmp_buf为sigjmp_buf
sigjmp_buf sjbuf;
void onintr(int);

void 
onintr(int i) 
{
    signal(SIGINT, onintr);
    printf("\nInterrupt(%d)\n", i);
    // siglongjmp第二个参数不能为0,标准要求返回值需非0
    siglongjmp(sjbuf, 1);
}

int 
main(int argc, char* argv[]) 
{
    int sleep_t = 1; 
    int ctr     = 0; 
    int timeout = 10;

    if (signal(SIGINT, SIG_IGN) != SIG_IGN)
        signal(SIGINT, onintr);

    // 第二个参数为1,表示保存当前信号掩码
    if (sigsetjmp(sjbuf, 1) == 0) {
        printf("Starting loop...\n");
    }

    while (ctr < timeout) {
        printf("Going to sleep for %d second(s)\n", sleep_t);
        ctr++;
        sleep(sleep_t);
    }

    printf("\n");
    return 0;
}

验证效果

修改后运行程序,每次按下Ctrl+C都会触发信号处理函数,不会出现后续信号被忽略的情况:

./a.out 
Starting loop...
Going to sleep for 1 second(s)
Going to sleep for 1 second(s)
^C
Interrupt(2)
Starting loop...
Going to sleep for 1 second(s)
^C
Interrupt(2)
Starting loop...
Going to sleep for 1 second(s)
...

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 07:20:38