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

fork和exec生成的子进程SIGHUP信号处理失效原因及解决方法

问题原因
  1. 信号掩码继承问题:当父进程的SIGHUP处理函数执行时,内核默认会将SIGHUP信号加入进程的信号阻塞掩码,直到处理函数返回才会解除阻塞。你在信号处理函数内部调用fork生成子进程,子进程会完整继承父进程的信号阻塞掩码,后续调用execve启动新的服务进程时,信号阻塞掩码会被保留不会重置。因此子进程即便在main函数中重新注册了SIGHUP处理函数,SIGHUP始终处于阻塞状态,收到信号后也不会触发处理逻辑。
  2. SA_RESETHAND标记隐患:你在注册信号时设置了SA_RESETHAND标记,该标记会让信号触发一次处理函数后,自动将信号的处理方式重置为默认行为(SIGHUP默认动作是终止进程),也会导致后续收到信号无法执行自定义处理逻辑。
  3. 代码潜在笔误:你定义的处理函数名为sighup_handler,但sigaction中赋值的sa_handler是restart_handler,如果是实际代码的笔误也会导致处理逻辑不生效。
解决方案

核心修复(必做)

在信号处理函数的子进程分支,执行execve前显式清空信号阻塞掩码,示例代码如下:

void sighup_handler(int signo) {
    pid_t pid = fork();
    if (pid < 0) {
        // 处理fork失败逻辑
        return;
    }
    if (pid == 0) {
        // 子进程分支:清空信号阻塞掩码
        sigset_t empty_mask;
        sigemptyset(&empty_mask);
        sigprocmask(SIG_SETMASK, &empty_mask, NULL);
        execve("./server", argv_cstr.get(), NULL);
        // exec执行失败直接退出,避免残留孤儿进程
        exit(EXIT_FAILURE);
    }
    // 父进程后续逻辑:比如退出原进程等
    ...
}

优化调整(建议)

  1. 移除SA_RESETHAND标记,你的重启场景需要每次收到SIGHUP都触发处理逻辑,该标记不符合需求。
  2. 如果不需要信号处理期间阻塞SIGHUP,也可以在注册信号时添加SA_NODEFER标记,避免处理函数执行期间SIGHUP被阻塞,从根源避免子进程继承到阻塞的SIGHUP掩码:
action.sa_flags |= SA_NODEFER;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 11:36:01