我正在使用ProcessBuilder启动子进程,并且如果父进程执行,则需要子进程退出。在正常情况下,我的代码正在正确地阻止孩子。但是,如果我导致操作系统杀死父级,则子级将继续运行。
有没有办法将子进程“绑定”到父进程,以便在父进程被终止时它会退出?
类似的问题:
答案 0 :(得分:35)
虽然您无法防止硬中止(例如Unix上的SIGKILL),但您可以防止导致父进程关闭的其他信号(例如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);
答案 1 :(得分:20)
子进程与其父进程之间没有关系。他们可能知道彼此的进程ID,但它们之间没有硬连接。你在谈论orphan process。这是操作系统级别的问题。意味着任何解决方案都可能取决于平
关于我唯一能想到的是让孩子定期检查其父母身份,如果父母关闭则退出。我不认为这会是那么可靠。
答案 2 :(得分:16)
您只需在子进程中启动从System.in读取的线程即可。如果你不是写你孩子的标准书,那么其他人都不会这样做,并且该主题将“永远”阻止。但是如果父进程被杀死或者死亡,你将获得EOF(或异常)。所以你也可以关闭孩子。 (子进程以java.lang.ProcessBuilder开头)
答案 3 :(得分:5)
提供与@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
当父进程退出时,子进程立即退出。
答案 4 :(得分:3)
您发现操作系统可以让您解决此问题。而是创建两个进程共享的资源。当父母中止资源时,孩子通过关闭做出反应。例如:
在随机高位端口上的父级上以接受模式创建一个服务器端TCP / IP套接字的线程。当孩子启动时,将端口号作为参数传递(环境变量,数据库条目,等等)。让它创建一个线程并打开该套接字。有线程永远坐在插座上。如果连接断开,请让孩子退出。
或
在父级上创建一个不断更新文件更新日期的线程。 (通常取决于您需要的kill和shutdown之间的粒度。)子进程有一个监视同一文件更新时间的线程。如果在特定时间间隔后没有更新,则自动关闭。
答案 5 :(得分:2)
对于单个子进程,您可以通过反转子/父关系来管理它。请参阅my answer以了解此问题的后续版本。
答案 6 :(得分:0)
当父级停止
时,尝试从父级向子进程发送一个kill信号答案 7 :(得分:0)
正如我测试的那样,如果父母被杀死,那么孩子的ppid将变为1.所以我们可以杀死任何有ppid = 1的进程。
答案 8 :(得分:0)
对于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;
}