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

如何实现由其他进程而非systemd接管孤儿进程(含Bash命令行与C程序实现方法)

如何实现由其他进程而非systemd接管孤儿进程(含Bash命令行与C程序实现方法)

嘿,刚好对这个点有研究,给你拆解一下具体实现方法!首先得提一句,Linux内核3.4版本之后支持PR_SET_CHILD_SUBREAPER这个特性,只要进程设置了这个属性,它就会成为「子收割者」,它的后代里出现的孤儿进程会被它接管,而不是默认的systemd(PID 1)。下面分Bash命令行和C程序两种场景给你一步步来:

Bash命令行实现方法

  1. 先启动一个后台进程作为「子收割者」,设置好subreaper属性后挂起:
# 启动subreaper进程,后台运行并挂起
bash -c 'prctl --set-subreaper 1; exec sleep infinity' &
# 记录这个收割者的PID,方便后续操作
REAPER_PID=$!
  1. 进入这个收割者的PID命名空间,启动一个新的shell:
nsenter --target $REAPER_PID --pid -- bash
  1. 在这个新shell里启动一个后台测试进程,然后退出当前shell:
# 启动一个后台sleep进程,模拟会变成孤儿的程序
sleep 60 &
# 退出当前shell,让sleep的父进程消失
exit
  1. 验证效果:用ps -o ppid= -p <sleep的PID>命令查看,会发现sleep的父PID是之前记录的REAPER_PID,而不是1(systemd的PID)。

C程序实现方法

直接通过prctl()系统调用给进程设置PR_SET_CHILD_SUBREAPER属性,然后创建多层子进程模拟孤儿场景,具体代码如下:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <sys/wait.h>

int main() {
    // 给当前进程设置子收割者属性
    if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0) == -1) {
        perror("prctl设置subreaper失败");
        exit(EXIT_FAILURE);
    }
    printf("子收割者进程PID:%d\n", getpid());

    // 第一层子进程
    pid_t child_pid = fork();
    if (child_pid == -1) {
        perror("创建子进程失败");
        exit(EXIT_FAILURE);
    }

    if (child_pid == 0) {
        // 子进程中创建孙子进程(后续会变成孤儿)
        pid_t grandchild_pid = fork();
        if (grandchild_pid == -1) {
            perror("创建孙子进程失败");
            exit(EXIT_FAILURE);
        }

        if (grandchild_pid == 0) {
            // 孙子进程:等待父进程退出,然后查看自己的父PID
            printf("孙子进程PID:%d,等待父进程退出...\n", getpid());
            sleep(2); // 留时间让父进程退出
            printf("父进程退出后,孙子进程的父PID变为:%d\n", getppid());
            sleep(10); // 保持运行,方便用ps命令验证
            exit(EXIT_SUCCESS);
        } else {
            // 子进程直接退出,让孙子进程变成孤儿
            printf("子进程PID:%d,现在退出...\n", getpid());
            exit(EXIT_SUCCESS);
        }
    } else {
        // 子收割者进程等待第一层子进程退出
        waitpid(child_pid, NULL, 0);
        printf("子收割者:子进程已退出,开始接管孤儿进程...\n");
        sleep(15); // 保持运行,方便验证
        exit(EXIT_SUCCESS);
    }
}

编译运行这个程序后,你会看到孙子进程的父PID变成了子收割者的PID,而不是systemd的PID 1,完美实现了我们要的效果。

备注:内容来源于stack exchange,提问作者tahzibi.jafar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 08:37:59