父母如何才能导致子进程退出?

问题描述:

我正在使用ProcessBuilder启动子进程,并且如果父进程需要子进程退出。在正常情况下,我的代码正确地停止了孩子。但是,如果我导致操作系统杀死父母,孩子将继续运行。父母如何才能导致子进程退出?

有什么办法可以将子进程“绑定”到父进程,从而在父进程被杀时退出?


类似的问题:

有一个子进程与其父之间没有打领带。他们可能知道对方的进程ID,但他们之间没有硬连接。你在说什么orphan process。这是操作系统级别的问题。意味着任何解决方案都可能取决于平台

我能想到的唯一的事情就是让孩子定期检查父母的状态,如果父母关机,退出。我认为这不会是可靠的。

+10

如果您正在轮询以查看子项的PPID是否为1,那么定期检查父项的状态可能是可靠的,因为孤立进程会获得init进程的PPID。 (PID = 1) – Aaron 2010-02-25 17:54:26

+1

如果有人想知道,在Android系统中,pid似乎是0(进程System pid)而不是1,当父母死亡时。 – 2012-10-02 17:39:03

+6

我刚刚通过一个简单的改进实现了“父级状态检查” - 我只是将原始parent_pid传递给子级,他们只是检查父级pid是否保持不变。所以它应该工作,无论init/systemd /任何pid数值。 – 2014-02-20 16:22:44

尝试将终止信号从父发送到子进程当父停止

+0

杀死一个进程通常不允许进行任何清理。这正是问题所在。 – sblundy 2008-11-06 17:32:33

虽然不能防止硬中断(例如SIGKILL在Unix),可以防止引起你的父母等信号进程关闭(例如SIGINT)并清理你的子进程。您可以通过使用关闭挂钩完成此操作:请参阅Runtime#addShutdownHook以及相关的SO问题here

您的代码可能是这个样子:

String[] command; 
final Process childProcess = new ProcessBuilder(command).start(); 

Thread closeChildThread = new Thread() { 
    public void run() { 
     childProcess.destroy(); 
    } 
}; 

Runtime.getRuntime().addShutdownHook(closeChildThread); 

单个儿童的过程,你可以通过反转父/子关系管理此。请参阅my answer,以获得此问题的后续版本。

正如您发现操作系统允许您解决此问题。相反,创建一个由两个进程共享的资源。当父母放弃资源时,孩子通过关闭做出反应。例如:

在接受模式下,在父节点的随机高数字端口上创建一个服务器端TCP/IP套接字的线程。当孩子开始时,传递端口号作为参数(环境变量,数据库条目,不管)。让它创建一个线程并打开该套接字。线程永远坐在插座上。如果连接断开,请让孩子退出。

创建于父线程,不断更新上的文件的更新日期。 (多长时间取决于您需要的kill和shutdown之间有多大的粒度)。子进程有一个线程,用于监视同一文件的更新时间。如果它在特定的时间间隔后没有更新,则自动关机。

您可以简单地在子进程中启动从System.in读取线程。如果你不写信给你的孩子的标准输入,没有人会这样做,线程会“永远”阻塞。但是如果父进程死亡或者死亡,你将得到一个EOF(或者一个异常)。所以你也可以关闭孩子。(子进程开始java.lang.ProcessBuilder中)

正如我测试过,如果父母被杀害,那么孩子的PPID将成为1.因此可能是我们可以杀死那些PPID = 1

任何进程

对于Windows,我想出了这个投票黑客:

static int getPpid(int pid) throws IOException { 
    Process p = Runtime.getRuntime().exec("C:\\Windows\\System32\\wbem\\WMIC.exe process where (processid="+pid+") get parentprocessid"); 
    BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())); 
    br.readLine(); 
    br.readLine(); 
    String ppid= br.readLine().replaceAll(" ",""); 
    return Integer.parseInt(ppid); 
} 
static boolean shouldExit() { 
    try { 
     String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0]; 
     int ppid = getPpid(Integer.parseInt(pid)); 
     /* pppid */ getPpid(ppid); 
    } catch (Exception e) { 
     return true; 
    } 
    return false; 
} 

提供黑客的方法是从@tomkri答案相似,并且也提供了演示代码。

如果您的子进程不需要使用输入流,只是将子进程输入流重定向到其父进程的输入流。然后,在子节点中添加一个线程,以便始终读取输入流,并且当此线程无法从输入流中读取任何内容时,此子进程将退出。所以父进程退出 - >父进程输入流不存在 - >子进程输入流不存在 - >子进程退出。

这里是所有使用Java的演示代码。

父进程:

package process.parent_child; 

import java.io.File; 
import java.io.IOException; 
import java.lang.ProcessBuilder.Redirect; 

public class ParentProc { 

    public static void main(String[] args) { 
     System.out.println("I'm parent."); 

     String javaHome = System.getProperty("java.home"); 
     String javaBin = javaHome + File.separator + "bin" + File.separator + "java"; 
     ProcessBuilder builder = new ProcessBuilder(javaBin, "process.parent_child.ChildProc"); 

     // Redirect subprocess's input stream to this parent process's input stream. 
     builder.redirectInput(Redirect.INHERIT); 
     // This is just for see the output of child process much more easily. 
     builder.redirectOutput(Redirect.INHERIT); 
     try { 
      Process process = builder.start(); 
      Thread.sleep(5000); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     System.out.println("Parent exits."); 
    } 
} 

子进程:

package process.parent_child; 

import java.io.IOException; 
import java.util.Scanner; 

public class ChildProc { 


    private static class StdinListenerThread extends Thread { 

     public void run() { 
      int c; 
      try { 
       c = System.in.read(); 
       while (c != -1) { 
        System.out.print(c); 
       } 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
      System.out.println("\nChild exits."); 
      System.exit(0); 
     } 
    } 

    public static void main(String[] args) throws InterruptedException { 
     System.out.println("I'm child process."); 
     StdinListenerThread thread = new StdinListenerThread(); 
     thread.start(); 
     Thread.sleep(10000); 
    } 
} 

通过运行以下命令,此父进程后:

java process.parent_child.ParentProc 

你会看到

I'm parent. 
    I'm child process. 
    Parent exits. 
    xmpy-mbp:bin zhaoxm$ 
    Child exits 

子进程在父进程退出时立即退出。