确保父进程终止时子进程终止很麻烦。我发现一种健壮的解决方案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二进制文件。

局限性是:

  • 这是一个简单的程序,如果您从子进程中启动其他内容,除非您设置了一些限制,否则它将可怕地杀死事物。
  • ,它不适用于可执行模型(例如32-> 64bit),这在
  • 中相对较少
  • 它不适用于静态链接的二进制文件(很少)

  • 考虑到这些限制,我们可以使用一些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/

    10-11 15:25