2008-11-06 22 views
33

Estoy iniciando un proceso secundario con ProcessBuilder, y necesito que el proceso hijo salga si lo hace el proceso padre. En circunstancias normales, mi código está deteniendo al niño correctamente. Sin embargo, si hago que el sistema operativo mate al padre, el niño continuará ejecutándose.¿Cómo puedo hacer que un proceso hijo salga cuando lo hace el padre?

¿Hay alguna forma de "vincular" el proceso secundario con el elemento principal, de modo que se cierre cuando se elimine al elemento primario?


preguntas similares:

Respuesta

16

No hay ningún vínculo entre un proceso hijo y su padre. Pueden conocer el ID de proceso del otro, pero no hay una conexión dura entre ellos. De lo que estás hablando es orphan process. Y es una preocupación de nivel de sistema operativo. Es decir, cualquier solución depende probablemente de la plataforma.

Lo único que se me ocurre es hacer que el niño verifique periódicamente el estado de sus padres, saliendo si el padre se apaga. Sin embargo, no creo que esto sea tan confiable.

+10

Comprobar el estado del padre periódicamente puede ser confiable si está encuestando para ver si el PPID del hijo se convierte en 1, ya que los procesos huérfanos obtienen un PPID del proceso init. (PID = 1) – Aaron

+1

Si alguien se pregunta, en los sistemas Android pid parece ser 0 (procesar System pid) en lugar de 1, cuando el padre muere. –

+6

Acabo de implementar esta "comprobación de estado parental" con una mejora simple: simplemente paso el original parent_pid a los niños y ellos simplemente comprueban si el pid padre permanece igual. Por lo tanto, debería funcionar independientemente del valor numérico pid/init/systemd/whatever. –

0

intenta enviar una señal kill al proceso hijo del padre cuando el padre se detiene

+0

Asesinar un proceso normalmente no permite ningún tipo de limpieza. Cuál es exactamente el problema. – sblundy

+0

Eso depende de cómo se mata un proceso y bajo qué sistema operativo. SIGTERM en Unixes permite que el programa haga la limpieza, SIGKILL no lo hace. – Powerlord

29

Si bien no se puede proteger contra un aborto duro (por ejemplo SIGKILL en Unix), puede proteger contra otras señales que hacen sus padres proceso para cerrar (por ejemplo, SIGINT) y limpiar el proceso de su hijo. Puede lograr esto mediante el uso de los ganchos de apagado: consulte Runtime#addShutdownHook, así como una pregunta relacionada con SO here.

Su código podría ser algo como esto:

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

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

Runtime.getRuntime().addShutdownHook(closeChildThread); 
2

Para un solo hijo procesos se puede administrar esta invirtiendo la relación hijo/padre. Ver my answer para una posterior encarnación de esta pregunta.

3

Como has encontrado, el sistema operativo te permite evitar este problema. En su lugar, cree un recurso compartido por ambos procesos. Cuando el padre aborta el recurso, el niño reacciona cerrándose. Por ejemplo:

Cree un subproceso con un socket TCP/IP del lado del servidor en el modo de aceptación en el elemento primario en un puerto de alto número aleatorio. Cuando el niño comienza, pase el número de puerto como parámetro (variable de entorno, entrada en la base de datos, lo que sea). Haga que cree un hilo y abra ese zócalo. Tienen el hilo sentado en el zócalo para siempre. Si la conexión se cae alguna vez, haga que el niño salga.

o

crear un hilo en el elemento principal que se actualiza de forma continua la fecha de actualización en un archivo. (La frecuencia con la que depende la cantidad de granularidad entre el cierre y el apagado que necesita). El niño tiene un hilo que supervisa el tiempo de actualización del mismo archivo. Si no se actualiza después de un intervalo específico, cierre automáticamente.

13

Simplemente puede iniciar una lectura de subprocesos desde System.in en el proceso secundario. Si no está escribiendo para stdin de su hijo, nadie más lo hará y el hilo bloqueará "para siempre". Pero obtendrá un EOF (o una excepción), si el proceso principal se mata o muere de lo contrario. Entonces puedes apagar al niño también.(Proceso Niño comenzó con java.lang.ProcessBuilder)

+0

Esta es una buena solución. Si la lectura se hace en un hilo. Recuerde configurar hilo deamon (verdadero) o el hilo evitará que el programa se cierre normalmente. –

0

Como ya he probado, si el padre muere, entonces el ppid de un niño se convierta en 1. Así que probablemente podemos interrumpir los procesos que han ppid = 1.

0

Para las ventanas, me ocurrió con este truco de votación:

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; 
} 
+0

Nice windows ruta codificada allí: D -1 – ArsenArsen

4

proporciona una forma de hackers que es similar a la respuesta de @tomkri y también proporcionan el código de demostración.

Si su proceso hijo no necesita el uso de la secuencia de entrada, simplemente redirija la secuencia de entrada del proceso secundario a la secuencia de entrada del proceso principal. A continuación, agregue un subproceso en el elemento secundario para leer siempre la secuencia de entrada y, cuando este subproceso no pueda leer nada de la secuencia de entrada, este proceso secundario finaliza. Entonces el proceso padre sale -> la corriente de entrada de los padres no existe -> la corriente de entrada del niño no existe -> el proceso hijo sale.

Aquí está el código de la demo, todo en Java.

proceso primario:

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."); 
    } 
} 

proceso hijo:

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); 
    } 
} 

Después de ejecutar este proceso los padres por el siguiente comando:

java process.parent_child.ParentProc 

verá

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

El proceso secundario sale inmediatamente cuando el proceso primario finaliza.

+0

buena solución, fue muy útil. –

Cuestiones relacionadas