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

C++中使用fork和kill导致Ubuntu崩溃的问题求助

问题分析与解决方案

嘿,这个问题我太熟悉了!核心原因是父进程退出后,你的子进程逻辑存在两个致命问题:

  1. 你在子进程刚fork时就获取了父进程ID并存在变量里,但如果父进程在sleep(time)期间退出,这个旧的PID可能被系统重新分配给其他进程(包括1号init/systemd进程),此时kill(id, 0)可能返回0(因为PID被复用了),导致你给完全无关的进程发送TIMEOUT信号——如果刚好是init进程,系统直接崩溃就不奇怪了。
  2. 即使PID没被复用,父进程退出后子进程会变成孤儿进程被init接管,此时你后续如果误操作给init发信号,同样会搞崩系统。

修复方案:用prctl让父进程主动通知子进程退出

最可靠的解决方式是利用Linux的prctl系统调用,让父进程在退出时自动给子进程发送一个终止信号,这样子进程就能及时退出,不会走到后续的危险逻辑。

修改后的代码如下:

#include <sys/prctl.h>
#include <signal.h>
#include <unistd.h>
#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

// 子进程的SIGTERM信号处理函数,收到后直接退出
void handle_sigterm(int sig) {
    exit(0);
}

void setTimeout(int time) {
    pid_t child_pid = fork();
    if (child_pid == 0) {
        // 注册信号处理函数,确保收到SIGTERM时立即退出
        signal(SIGTERM, handle_sigterm);
        
        // 设置:当父进程退出时,给当前子进程发送SIGTERM信号
        prctl(PR_SET_PDEATHSIG, SIGTERM);
        
        // 双重保险:检查父进程是否还存活(防止fork后父进程立即退出,prctl还没生效)
        pid_t parent_id = getppid();
        if (kill(parent_id, 0) == ESRCH) {
            exit(0);
        }
        
        sleep(time);
        
        // 再次检查父进程状态
        parent_id = getppid();
        if (kill(parent_id, 0) == ESRCH) {
            return;
        }
        
        std::cerr << "Time out!" << std::endl;
        kill(parent_id, TIMEOUT);
        return;
    }
    // 父进程可以根据需要回收子进程资源,避免僵尸进程
    // waitpid(child_pid, NULL, WNOHANG);
}

为什么这个方案有效?

  • PR_SET_PDEATHSIG会让内核监控父进程的状态,一旦父进程退出,内核会自动给子进程发送指定的信号(这里用SIGTERM),子进程收到后直接退出,不会执行后续的kill操作。
  • 两次kill(parent_id, 0)的检查是双重保险,防止极端情况下prctl还没生效父进程就退出的场景。
  • 避免了PID复用带来的误操作问题,因为我们不再依赖fork时保存的旧PID,而是每次检查当前的父进程ID。

另外,记得在父进程中适当回收子进程资源(比如用waitpid加WNOHANG选项),避免产生僵尸进程哦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:53:05