Как я могу заставить дочерний процесс завершить работу родителя?
Я запускаю дочерний процесс с ProcessBuilder и нуждаюсь, чтобы дочерний процесс завершался, если родительский процесс. При нормальных обстоятельствах мой код правильно останавливает ребенка. Однако, если я заставляю ОС убивать родителя, ребенок будет продолжать работать.
Есть ли способ "связать" дочерний процесс с родителем, чтобы он выходил, когда родитель был убит?
Похожие вопросы:
Ответы
Ответ 1
Между дочерним процессом и его родителем нет связи. Они могут знать, что каждый из них обрабатывает идентификатор, но между ними нет жесткой связи. Что вы говорите о сиротском процессе. И это касается уровня ОС. Значение любого решения, вероятно, зависит от платформы.
О единственном, что я могу придумать, - это периодически проверять статус родителя, выходя из него, если выключение родителя. Я не думаю, что это было бы все надежнее, хотя.
Ответ 2
Пока вы не можете защитить от жесткого прерывания (например, SIGKILL в Unix), вы можете защитить от других сигналов, которые заставляют ваш родительский процесс закрываться (например, SIGINT) и очищать ваш дочерний процесс. Вы можете это сделать, используя крючки остановки: см. Runtime # addShutdownHook, а также связанный с ним вопрос SO .
Ваш код может выглядеть примерно так:
String[] command;
final Process childProcess = new ProcessBuilder(command).start();
Thread closeChildThread = new Thread() {
public void run() {
childProcess.destroy();
}
};
Runtime.getRuntime().addShutdownHook(closeChildThread);
Ответ 3
Вы можете просто начать чтение потока из System.in в дочернем процессе. Если вы не пишете на stdin вашего ребенка, никто не будет делать этого, и поток будет блокировать "навсегда". Но вы получите EOF (или исключение), если родительский процесс убит или погибнет иначе. Таким образом, вы также можете выключить ребенка. (Детский процесс начинается с java.lang.ProcessBuilder)
Ответ 4
Предоставьте хакерский путь, похожий на ответ от @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 input stream to this parent process 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
Детский процесс завершается сразу же после выхода родительского процесса.
Ответ 5
Как вы нашли, операционная система позволяет обойти эту проблему. Вместо этого создайте ресурс, совместно используемый обоими процессами. Когда родитель прерывает ресурс, ребенок реагирует путем выключения. Например:
Создайте поток с серверным TCP/IP-сокером в режиме приема родителя на случайном большом номере. Когда ребенок начинает, передайте номер порта в качестве параметра (переменная среды, запись базы данных, что угодно). Создайте поток и откройте этот сокет. У них есть нить, сидящая на гнезде навсегда. Если соединение когда-либо падает, выйдите из него.
или
Создайте поток родителя, который постоянно обновляет дату обновления файла. (Как часто зависит от того, насколько нужна гранулярность между убийством и выключением). У ребенка есть поток, который контролирует время обновления одного и того же файла. Если он не обновляется через определенный интервал, автоматически отключается.
Ответ 6
Для одного дочернего процесса вы можете управлять этим путем инверсии отношения child/parent. См. мой ответ для более позднего воплощения этого вопроса.
Ответ 7
Попробуйте отправить сигнал убития дочернему процессу из родителя, когда родитель останавливает
Ответ 8
Как я тестировал, если родитель убит, тогда ppid для ребенка станет 1. Поэтому, возможно, мы сможем убить любые процессы с ppid = 1.
Ответ 9
Для окон я придумал этот опрос:
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;
}