SIGKILL 到父进程终止时的子进程树

SIGKILL to a subprocess tree on parent termination

我有一个启动多个第 3 方可执行文件(所有封闭源代码和不可修改)的守护进程应用程序。

我想让所有子进程在父进程因任何原因退出时自动终止(包括崩溃)。

目前,我正在使用 prctl 来实现这一点(另请参阅 this 问题):

int ret = fork();
if (ret == 0) {
    //Setup other stuff
    prctl (PR_SET_PDEATHSIG, SIGKILL);

    if (execve( "childexecutable" ) < 0) { /*signal error*/}
}

但是,如果“childexecutable”也分叉并生成“grandchildren”,那么当我的进程退出时“grandchildren”不会被杀死。

也许我可以创建一个充当 subreaper 的中间进程,当我的进程死掉时它会杀死“someexecutable”,然后等待 SIGCHLD 并继续杀死子进程直到 none剩下了,不过好像脆。

有没有更好的解决方案?

在这种情况下创建一个 subreaper 是没有用的,你的 grandchildren 无论如何都会被 parent 重新parent并被 init 收割。

然而你可以做的是:

  1. 启动一个 parent 进程并立即 fork 一个 child。
  2. parent 将简单地 wait 用于 child。
  3. child 将执行您实际程序的所有工作,包括通过 fork + execve.
  4. 生成任何其他 children
  5. 一旦 child 出于任何原因(包括死亡信号,例如崩溃)退出,parent 可以发出 kill(0, SIGKILL)killpg(getpgid(0), SIGKILL) 来终止所有进程它的过程组。在 SIGKILL 之前发出 SIGINT/SIGTERM 可能是一个更好的主意,具体取决于您想要 运行 的 child 进程,因为它们可以处理此类信号和在退出之前对已用资源(包括 children)进行优雅清理。

假设 children 或 grandchildren 的 none 在 运行ning 时更改了它们的进程组,这将在退出时杀死整个进程树你的程序。您还可以将 PR_SET_PDEATHSIG 保留在任何 execve 之前,以使其更加稳健。再次取决于您想要 运行 的 PR_SET_PDEATHSIGSIGINT/SIGTERM 的过程可能比 SIGKILL.

更有意义

您可以在执行上述任何操作之前发出 setpgid(getpid(), 0) 来为您的程序创建一个新的进程组,并避免在发出 kill(0, SIGKILL).[=32= 时杀死任何 parents ]

“parent”过程的逻辑应该非常简单,只是循环中的 fork + wait + kill 返回的正确条件wait。当然,如果这个过程也崩溃了,那么所有的赌注都没有了,所以在编写简单可靠的代码时要小心。