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

sigprocmask结合SIG_BLOCK无法阻塞SIGALRM的原因排查求助

嘿,我来帮你排查这个sigprocmask阻塞SIGALRM失效的问题!

首先,核心原因大概率和你使用的POSIX定时器的通知方式有关,我给你拆解下可能的问题点:

1. 你是不是用了线程式的定时器通知?

如果你的timer_create调用里,把sigevent结构的sigev_notify设置成了SIGEV_THREAD或者SIGEV_THREAD_ID,那定时器触发时,系统会直接创建一个新线程(或者指定线程)来执行你的信号处理函数——这种方式完全绕过了进程的信号掩码机制!

也就是说,sigprocmask只能管得住通过信号队列投递的信号,管不住直接跑在新线程里的处理逻辑,这就会出现你看到的“明明阻塞了信号,handler还是被调用”的情况。

2. 确认sigprocmask的调用是否正确

如果你确实用的是SIGEV_SIGNAL(信号投递方式),那得检查sigprocmask的调用有没有坑:

  • 有没有正确把SIGALRM加入到要阻塞的信号集里?
  • 用的是SIG_BLOCK还是SIG_SETMASK?如果是SIG_SETMASK,有没有不小心覆盖了默认的信号掩码?
  • 有没有调用失败?记得加perror排查错误。

比如正确的阻塞代码应该是这样的:

sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
    perror("sigprocmask");
    exit(EXIT_FAILURE);
}

给你一个可验证的示例代码

你可以试试下面这个完整的例子,对比两种通知方式的差异:

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

timer_t timer_ID;

static void timer_handler(int signo, siginfo_t *sig_info, void *sig_ucontext) {
    printf("Handler triggered!\n");
}

int main() {
    // 注册带siginfo的信号处理函数
    struct sigaction sa;
    sa.sa_sigaction = timer_handler;
    sa.sa_flags = SA_SIGINFO;
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGALRM, &sa, NULL) == -1) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }

    // 阻塞SIGALRM
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGALRM);
    if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
        perror("sigprocmask");
        exit(EXIT_FAILURE);
    }

    struct sigevent sev;
    // 测试1:用信号投递方式(sigprocmask能生效)
    sev.sigev_notify = SIGEV_SIGNAL;
    // 测试2:用线程方式(sigprocmask完全无效,注释上面一行,打开下面一行)
    // sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_signo = SIGALRM;
    sev.sigev_value.sival_ptr = &timer_ID;

    if (timer_create(CLOCK_REALTIME, &sev, &timer_ID) == -1) {
        perror("timer_create");
        exit(EXIT_FAILURE);
    }

    // 设置定时器1秒后开始,每秒触发一次
    struct itimerspec its;
    its.it_value.tv_sec = 1;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 1;
    its.it_interval.tv_nsec = 0;

    if (timer_settime(timer_ID, 0, &its, NULL) == -1) {
        perror("timer_settime");
        exit(EXIT_FAILURE);
    }

    printf("Timer started, SIGALRM blocked. Sleeping 5s...\n");
    sleep(5);

    // 解除阻塞(如果是信号投递方式,这里会触发一次handler)
    sigprocmask(SIG_UNBLOCK, &mask, NULL);
    printf("Unblocked SIGALRM, waiting 2s...\n");
    sleep(2);

    timer_delete(timer_ID);
    return 0;
}

总结排查步骤

  1. 先去看你的timer_create代码,重点看sigev_notify的取值——如果是SIGEV_THREAD,那就是这个导致的问题,换成SIGEV_SIGNAL就能让sigprocmask生效。
  2. 如果已经是SIGEV_SIGNAL,那就检查sigprocmask的调用逻辑,确保信号集设置正确、调用没有失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:38:13