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

为何设置SA_RESETHAND标志的C代码会响应两次SIGUSR1信号?

为何设置SA_RESETHAND标志的C代码会响应两次SIGUSR1信号?

嘿,我来帮你捋清楚这个问题哈!

首先,你可能对SA_RESETHAND标志的生效时机理解错了——它不是在自定义信号处理函数执行前就移除处理逻辑,而是要等处理函数执行完毕、正常返回之后,才会把该信号的处理动作恢复成系统默认的SIG_DFL。这是第一个容易踩的坑。

那为什么你的代码会响应两次信号呢?主要有两个常见原因:

  • 第一,信号处理期间的阻塞逻辑没做好
    你在声明struct sigaction sa的时候,直接设置了sa_handler和sa_flags,但没初始化sa_mask成员。这个成员是用来指定信号处理期间需要阻塞的信号集合,如果你不初始化它,里面会是随机的垃圾值。要是刚好这个随机值里没包含SIGUSR1,那在第一次处理信号的过程中,操作系统不会阻塞新的SIGUSR1信号——这时候如果再收到同一个信号,就会直接再次触发你的自定义处理函数,自然就出现了“响应两次”的情况。

  • 第二,信号递送的时序问题
    如果你是连续发送了两次SIGUSR1信号,第一次信号触发自定义处理后,第二次信号会被操作系统挂起(如果sa_mask正确包含了SIGUSR1的话)。等第一次处理函数执行完,处理动作恢复成默认,这时候挂起的第二次信号会被递送,执行默认动作(比如终止程序)。要是你只看signal_handled变量的变化,可能会误以为是自定义处理函数被执行了两次,但其实第二次是系统默认动作在生效。

要解决这个问题,你只需要把sigaction结构体的所有成员都正确初始化就行,给你修正后的代码参考:

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

int signal_handled = 0;

void sighandler(int sig) {
    signal_handled++;
    printf("信号已处理!计数:%d\n", signal_handled);
}

int main(int args, char** argv) {
    struct sigaction sa;
    // 先清空整个结构体,避免未初始化的垃圾值干扰
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = &sighandler;
    sa.sa_flags = SA_RESETHAND;
    // 显式添加SIGUSR1到阻塞掩码,处理期间不再接收该信号
    sigaddset(&sa.sa_mask, SIGUSR1);

    if (sigaction(SIGUSR1, &sa, NULL) == -1) {
        perror("sigaction 调用失败");
        return 1;
    }

    printf("等待SIGUSR1信号...\n");
    // 等待信号触发
    while (signal_handled < 1) {
        pause();
    }
    printf("自定义处理函数已执行一次,现在已恢复为默认处理动作\n");
    // 此时再发SIGUSR1会触发默认终止动作
    pause();
    return 0;
}

简单来说,核心就是:SA_RESETHAND是处理完才复位,一定要正确初始化sigaction的所有成员,尤其是信号阻塞掩码,这样就能符合你的预期啦!

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 13:48:01