父母如何才能导致子进程退出?
我正在使用ProcessBuilder启动子进程,并且如果父进程需要子进程退出。在正常情况下,我的代码正确地停止了孩子。但是,如果我导致操作系统杀死父母,孩子将继续运行。父母如何才能导致子进程退出?
有什么办法可以将子进程“绑定”到父进程,从而在父进程被杀时退出?
类似的问题:
有一个子进程与其父之间没有打领带。他们可能知道对方的进程ID,但他们之间没有硬连接。你在说什么orphan process。这是操作系统级别的问题。意味着任何解决方案都可能取决于平台
我能想到的唯一的事情就是让孩子定期检查父母的状态,如果父母关机,退出。我认为这不会是可靠的。
虽然不能防止硬中断(例如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);
正如您发现操作系统允许您解决此问题。相反,创建一个由两个进程共享的资源。当父母放弃资源时,孩子通过关闭做出反应。例如:
在接受模式下,在父节点的随机高数字端口上创建一个服务器端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
子进程在父进程退出时立即退出。
如果您正在轮询以查看子项的PPID是否为1,那么定期检查父项的状态可能是可靠的,因为孤立进程会获得init进程的PPID。 (PID = 1) – Aaron 2010-02-25 17:54:26
如果有人想知道,在Android系统中,pid似乎是0(进程System pid)而不是1,当父母死亡时。 – 2012-10-02 17:39:03
我刚刚通过一个简单的改进实现了“父级状态检查” - 我只是将原始parent_pid传递给子级,他们只是检查父级pid是否保持不变。所以它应该工作,无论init/systemd /任何pid数值。 – 2014-02-20 16:22:44