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
收割。
然而你可以做的是:
- 启动一个 parent 进程并立即
fork
一个 child。
- parent 将简单地
wait
用于 child。
- child 将执行您实际程序的所有工作,包括通过
fork
+ execve
. 生成任何其他 children
- 一旦 child 出于任何原因(包括死亡信号,例如崩溃)退出,parent 可以发出
kill(0, SIGKILL)
或 killpg(getpgid(0), SIGKILL)
来终止所有进程它的过程组。在 SIGKILL
之前发出 SIGINT
/SIGTERM
可能是一个更好的主意,具体取决于您想要 运行 的 child 进程,因为它们可以处理此类信号和在退出之前对已用资源(包括 children)进行优雅清理。
假设 children 或 grandchildren 的 none 在 运行ning 时更改了它们的进程组,这将在退出时杀死整个进程树你的程序。您还可以将 PR_SET_PDEATHSIG
保留在任何 execve
之前,以使其更加稳健。再次取决于您想要 运行 的 PR_SET_PDEATHSIG
与 SIGINT
/SIGTERM
的过程可能比 SIGKILL
.
更有意义
您可以在执行上述任何操作之前发出 setpgid(getpid(), 0)
来为您的程序创建一个新的进程组,并避免在发出 kill(0, SIGKILL)
.[=32= 时杀死任何 parents ]
“parent”过程的逻辑应该非常简单,只是循环中的 fork
+ wait
+ kill
返回的正确条件wait
。当然,如果这个过程也崩溃了,那么所有的赌注都没有了,所以在编写简单可靠的代码时要小心。
我有一个启动多个第 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
收割。
然而你可以做的是:
- 启动一个 parent 进程并立即
fork
一个 child。 - parent 将简单地
wait
用于 child。 - child 将执行您实际程序的所有工作,包括通过
fork
+execve
. 生成任何其他 children
- 一旦 child 出于任何原因(包括死亡信号,例如崩溃)退出,parent 可以发出
kill(0, SIGKILL)
或killpg(getpgid(0), SIGKILL)
来终止所有进程它的过程组。在SIGKILL
之前发出SIGINT
/SIGTERM
可能是一个更好的主意,具体取决于您想要 运行 的 child 进程,因为它们可以处理此类信号和在退出之前对已用资源(包括 children)进行优雅清理。
假设 children 或 grandchildren 的 none 在 运行ning 时更改了它们的进程组,这将在退出时杀死整个进程树你的程序。您还可以将 PR_SET_PDEATHSIG
保留在任何 execve
之前,以使其更加稳健。再次取决于您想要 运行 的 PR_SET_PDEATHSIG
与 SIGINT
/SIGTERM
的过程可能比 SIGKILL
.
您可以在执行上述任何操作之前发出 setpgid(getpid(), 0)
来为您的程序创建一个新的进程组,并避免在发出 kill(0, SIGKILL)
.[=32= 时杀死任何 parents ]
“parent”过程的逻辑应该非常简单,只是循环中的 fork
+ wait
+ kill
返回的正确条件wait
。当然,如果这个过程也崩溃了,那么所有的赌注都没有了,所以在编写简单可靠的代码时要小心。