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

C语言中sigset无法阻塞SIGUSR1信号的问题求助

问题:sigaction的sa_mask未按预期阻塞SIGUSR1信号

你编写代码尝试用sigaction的sa_mask实现信号阻塞:为SIGINT设置处理函数,同时在其sa_mask中添加SIGUSR1,期望处理SIGINT时阻塞SIGUSR1;另外为SIGUSR1设置处理函数,主循环中定时用raise()发送SIGUSR1。但实际运行时,按下Ctrl+C后,SIGUSR1仍会被触发,输出交替出现"ctrl c"和"user sig"。

代码重现

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

void handler(int sig) {
    printf("ctrl c\n");
}

void handler1(int sig) {
    printf("user sig\n");
}

int main() {
    struct sigaction a;
    a.sa_handler = &handler;
    sigemptyset(&a.sa_mask);
    sigaddset(&a.sa_mask, SIGUSR1); 
    a.sa_flags = 0;

    struct sigaction b;
    b.sa_handler = &handler1;
    sigemptyset(&b.sa_mask); 
    b.sa_flags = 0;

    sigaction(SIGINT, &a, NULL);
    sigaction(SIGUSR1, &b, NULL);

    while (1) {
        sleep(1);
        raise(SIGUSR1);
    }

    return 0;
}

问题原因

你误解了sa_mask的作用范围:sigaction的sa_mask仅在当前信号的处理函数执行期间生效,也就是只有当SIGINT的handler函数正在运行时,SIGUSR1才会被阻塞。

你的代码中,每次按下Ctrl+C触发SIGINT后,handler函数执行完毕就会返回主循环,主循环里立刻调用raise(SIGUSR1)发送信号,此时sa_mask已经失效,所以SIGUSR1会被正常处理,导致输出交替出现。

解决方案

如果你希望在处理SIGINT的过程中(包括处理完成后一段时间)阻塞SIGUSR1,有两种常见实现方式:

方式1:用全局标志控制主循环的SIGUSR1发送

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

volatile sig_atomic_t block_usr1 = 0;

void handler(int sig) {
    printf("ctrl c\n");
    block_usr1 = 1;
    // 模拟阻塞SIGUSR1的时长
    sleep(3);
    block_usr1 = 0;
}

void handler1(int sig) {
    printf("user sig\n");
}

int main() {
    struct sigaction a;
    a.sa_handler = &handler;
    sigemptyset(&a.sa_mask);
    sigaddset(&a.sa_mask, SIGUSR1); // 确保handler执行期间SIGUSR1被阻塞
    a.sa_flags = 0;

    struct sigaction b;
    b.sa_handler = &handler1;
    sigemptyset(&b.sa_mask); 
    b.sa_flags = 0;

    sigaction(SIGINT, &a, NULL);
    sigaction(SIGUSR1, &b, NULL);

    while (1) {
        sleep(1);
        if (!block_usr1) {
            raise(SIGUSR1);
        }
    }

    return 0;
}

通过全局标志block_usr1控制主循环是否发送SIGUSR1,同时保留sa_mask确保处理SIGINT的过程中不会被SIGUSR1打断。

方式2:用sigprocmask修改全局信号掩码

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

void handler(int sig) {
    printf("ctrl c\n");
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGUSR1);
    // 全局阻塞SIGUSR1
    sigprocmask(SIG_BLOCK, &mask, NULL);
    sleep(3);
    // 解除全局阻塞
    sigprocmask(SIG_UNBLOCK, &mask, NULL);
}

void handler1(int sig) {
    printf("user sig\n");
}

int main() {
    struct sigaction a;
    a.sa_handler = &handler;
    sigemptyset(&a.sa_mask);
    a.sa_flags = 0;

    struct sigaction b;
    b.sa_handler = &handler1;
    sigemptyset(&b.sa_mask); 
    b.sa_flags = 0;

    sigaction(SIGINT, &a, NULL);
    sigaction(SIGUSR1, &b, NULL);

    while (1) {
        sleep(1);
        raise(SIGUSR1);
    }

    return 0;
}

直接调用sigprocmask修改进程的全局信号掩码,在指定时间段内完全阻塞SIGUSR1,不受信号处理函数执行状态的限制。

验证效果

使用任意一种方式后,按下Ctrl+C会输出"ctrl c",之后的3秒内不会输出"user sig",3秒后恢复正常发送SIGUSR1,符合信号阻塞的预期效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 15:33:29