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

如何避免子进程因信号终止时父进程随之终止?

问题分析与解决

问题背景

我希望生成一个进程并通过标准输入/输出与其通信,功能运行正常,但发现当子进程因信号终止时,父进程也会随之终止。以下为示例代码:

  • 取消注释/usr/bin/true时,程序会输出"Finish";
  • 编译并取消注释/tmp/selfterm时,程序不会输出该内容,且父进程会以退出码137终止。

请问父进程终止的原因是什么,该如何避免?


示例代码

main.c

#include <signal.h>
#include <sched.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>

int doexec(void*) {
    //char*bin = "/usr/bin/true";
    //char*bin = "/tmp/selfterm";
    char*args[] = {bin, 0};
    int err = execv(bin, args);
    return err;
}

int main(int argc, char *argv[]) {
    int pid = clone(doexec, malloc(2*1024*1024)+2*1024*1024, CLONE_VFORK|SIGCHLD, 0);
    int status=0;
    wait(&status);
    puts("Finish");
}

selfterm.c

#include<signal.h>
int main(int argc, char *argv[]) { kill(0, 9); }

父进程终止的原因

  1. kill(0, 9)的作用机制:kill(0, SIGKILL)会向当前进程组内的所有进程发送SIGKILL信号(信号9)。由于你用clone(CLONE_VFORK)创建的子进程默认和父进程属于同一个进程组,所以子进程执行kill(0,9)时,会把父进程也一并杀死。
  2. 退出码137的含义:Linux下进程被信号终止时,退出码为128 + 信号编号。137 = 128 + 9,明确说明父进程是被SIGKILL信号强制终止的。

解决方法

方法1:让子进程脱离父进程的进程组(推荐,无需root)

在子进程执行execv之前,调用setpgid(0, 0)创建一个新的进程组,让子进程成为该组的组长。这样kill(0,9)只会发送给子进程自己的进程组,不会影响父进程。

修改后的doexec函数:

int doexec(void*) {
    //char*bin = "/usr/bin/true";
    char*bin = "/tmp/selfterm";
    // 创建新进程组,子进程作为组长
    setpgid(0, 0);
    char*args[] = {bin, 0};
    int err = execv(bin, args);
    return err;
}

注意:setpgid必须放在execv之前,因为execv会替换整个进程镜像,之后的代码不会被执行。

方法2:使用PID命名空间隔离(需要root权限)

如果需要更强的进程隔离,可以在clone的参数中添加CLONE_NEWPID,创建一个独立的PID命名空间。子进程在这个命名空间内是PID 1,kill(0,9)只会影响命名空间内的进程,完全不会波及父进程。但这种方式需要root权限,适合容器类场景。

修改后的clone调用:

int pid = clone(doexec, malloc(2*1024*1024)+2*1024*1024, CLONE_VFORK|SIGCHLD|CLONE_NEWPID, 0);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 12:03:11