确保父进程终止时子进程终止是棘手的。我发现一个强大的解决方案from Python in Linux是指示内核在父进程使用prctl(PR_SET_PDEATHSIG, SIGTERM)
终止时终止子进程。考虑到prctl()
来自C标准库,大概可能从C或C ++开始。
有几个关于如何在Java中杀死子进程的问题,请参阅例如[1]。
但是,我发现的任何内容都不如使用prctl()
的方法强大。如果父接收SIGKILL,或者他们需要修改子代码,大多数解决方案将失败。通过让操作系统为我们完成工作,无论父进程发生什么情况,都会成功终止子进程,并且不需要修改子代码。
如何在从Java ProcessBuilder中生成的子进程中调用prctl(PR_SET_PDEATHSIG, SIGTERM)
?
答案 0 :(得分:3)
你可以用一点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的完整路径注入到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
。
这有点难看,但应该解决这个问题。