确保父进程终止时子进程终止很麻烦。我发现一种健壮的解决方案from Python in Linux可以指示内核在父进程使用prctl(PR_SET_PDEATHSIG, SIGTERM)
终止时杀死其子进程。考虑到prctl()
来自C标准库,从C或C++可能也有可能。
关于如何杀死Java中的子进程有几个问题,请参见例如[1]。
但是,我发现没有什么比使用prctl()
的方法更强大。如果父级收到SIGKILL或要求修改子级代码,则大多数解决方案将失败。通过使操作系统为我们完成任务,无论父级发生什么事情, child 都将始终被成功杀死,并且无需修改子级代码。
如何在Java ProcessBuilder生成的子进程中调用prctl(PR_SET_PDEATHSIG, SIGTERM)
?
最佳答案
只要您不担心一些条件,并且知道它会有局限性,就可以用一点C来完成。prctl(PR_SET_PDEATHSIG, …)
系统调用是linux内核的一部分,它具有一些规则-它不能在fork()
中生存,也不能在exec()
中存入setuid/setgid二进制文件。
局限性是:
考虑到这些限制,我们可以使用一些
C
创建一个小的预加载库,该库将调用此系统调用。因此,例如:#include <sys/prctl.h>
#include <sys/types.h>
#include <signal.h>
__attribute__((constructor))
static void on_load() {
prctl(PR_SET_PDEATHSIG, SIGTERM);
}
使用
gcc -fPIC -shared -o term_death.so term_death.c
编译当您将
LD_PRELOAD
环境变量与该二进制文件的完整路径一起使用时,启动的所有程序在其父进程被杀死时都将被发送SIGTERM
。这是从C端进行的设置-我们现在有一个帮助程序库,该库将允许您要求的行为。
让它从Java端开始工作。
我们需要将.so的完整路径注入(inject)到ProcessBuilder的
LD_PRELOAD
环境变量中,如下所示:ProcessBuilder pb = new ProcessBuilder();
Map<String, String> env = pb.environment();
env.put("LD_PRELOAD", "/home/me/development/experiments/term_death.so");
同样,您需要指定
.so
的路径,以便可以加载它。当您使用
pb.start()
时,它将继承LD_PRELOAD
环境变量。在加载可执行文件时,它运行on_load
代码(因为它被标记为构造函数),并说当父进程终止时,该进程将收到SIGTERM
。这有点难看,但是应该解决这个问题。
关于java - Java : How to call prctl() in child process,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33480932/