Как я могу заставить дочерний процесс завершить работу родителя?

Я запускаю дочерний процесс с 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;
}