假设我有一个进程,它只生成一个子进程。现在,当父进程由于某种原因(正常或不正常,通过kill, ^C,断言失败或其他任何原因)退出时,我希望子进程死亡。如何正确地做到这一点?


关于stackoverflow的一些类似问题:

(前面问过)当父进程退出的时候,我怎么能让子进程退出呢? (稍后问)用fork()创建的子进程会在父进程被杀死时自动被杀死吗?


关于Windows的stackoverflow也有类似的问题:

如何在Windows中自动销毁子进程? 当父进程被杀死时,杀死子进程


当前回答

如果你发送一个信号到pid 0,使用for实例

kill(0, 2); /* SIGINT */

该信号被发送到整个进程组,从而有效地杀死了子进程。

你可以很容易地测试它,比如:

(cat && kill 0) | python

如果你然后按^D,你会看到文本“Terminated”,这表明Python解释器确实已经被杀死,而不是因为stdin被关闭而退出。

其他回答

我在过去通过在“子”中运行“原始”代码和在“父”中运行“衍生”代码来实现这一点(也就是说:你在fork()之后反转了通常意义上的测试)。然后在“衍生”代码中捕获SIGCHLD…

对你来说可能不行,但管用的时候很可爱。

安装一个陷阱处理程序来捕获SIGINT,如果你的子进程还活着,它就会杀死它,尽管其他的帖子是正确的,它不会捕获SIGKILL。

以独占访问的方式打开一个.lockfile,并让子进程尝试打开它——如果打开成功,子进程应该退出

正如其他人指出的那样,当父进程退出时,依赖父进程pid变成1是不可移植的。不需要等待特定的父进程ID,只需要等待ID发生变化:

pit_t pid = getpid();
switch (fork())
{
    case -1:
    {
        abort(); /* or whatever... */
    }
    default:
    {
        /* parent */
        exit(0);
    }
    case 0:
    {
        /* child */
        /* ... */
    }
}

/* Wait for parent to exit */
while (getppid() != pid)
    ;

如果不想以全速轮询,可以根据需要添加微睡眠。

在我看来,这个选项比使用管道或依赖于信号更简单。

我正在尝试解决同样的问题,但由于我的程序必须运行在OS X上,所以只运行linux的解决方案对我不起作用。

我得到了与本页其他人相同的结论——当父母去世时,没有一种与posix兼容的方式来通知孩子。所以我想出了次好的办法——让孩子投票。

当父进程(由于任何原因)终止时,子进程将变成进程1。如果子进程只是定期轮询,它可以检查父进程是否为1。如果是,子进程应该退出。

这不是很好,但它可以工作,并且比本文其他地方建议的TCP套接字/锁文件轮询解决方案更容易。

另一种Linux特有的方法是在一个新的PID名称空间中创建父进程。然后它将是该名称空间中的PID 1,当它退出时,它的所有子节点将立即被SIGKILL杀死。

不幸的是,为了创建一个新的PID名称空间,您必须拥有CAP_SYS_ADMIN。但是,这种方法非常有效,在初始启动父进程之后不需要对父进程或子进程进行任何实际更改。

请参见clone(2)、pid_namespaces(7)和unshare(2)。