确保子进程在父进程终止时终止是很棘手的。我在 Linux 中从 Python 中找到了一个强大的解决方案,即当父进程使用prctl(PR_SET_PDEATHSIG, SIGTERM). 考虑到prctl()来自 C 标准库,C 或 C++ 可能也是如此。
关于如何在 Java 中杀死子进程有几个问题,参见例如[1]。但是,我发现没有什么比使用prctl(). 如果父级收到 SIGKILL,或者他们需要修改子级代码,大多数解决方案都会失败。通过让操作系统为我们完成这项工作,无论父级发生什么,子级总是会被成功杀死,并且子级代码不需要修改。
如何调用prctl(PR_SET_PDEATHSIG, SIGTERM)从 Java ProcessBuilder 产生的子进程?
你可以用一点 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);
}
Run Code Online (Sandbox Code Playgroud)
编译使用 gcc -fPIC -shared -o term_death.so term_death.c
当您使用LD_PRELOAD带有此二进制文件完整路径的环境变量时,任何启动的程序都将在SIGTERM其父进程被终止时发送。
这是 C 端的设置 - 我们现在有一个帮助库,它将允许您要求的行为。
从 java 端开始工作。
我们需要将 .so 的完整路径注入LD_PRELOADProcessBuilder的环境变量中,例如:
ProcessBuilder pb = new ProcessBuilder();
Map<String, String> env = pb.environment();
env.put("LD_PRELOAD", "/home/me/development/experiments/term_death.so");
Run Code Online (Sandbox Code Playgroud)
同样,您需要指定 的路径,.so以便可以加载它。
当您pb.start()将继承LD_PRELOAD环境变量时。在加载可执行文件时,它运行on_load代码(因为它被标记为构造函数)并表示该进程将SIGTERM在父进程终止时收到一个。
这有点难看,但应该解决这个问题。
| 归档时间: |
|
| 查看次数: |
761 次 |
| 最近记录: |