2010-07-19 34 views
28

He intentado usar Java ProcessBuilder para iniciar una aplicación en Linux que debería ejecutarse "a largo plazo". La forma en que se ejecuta este programa es lanzar un comando (en este caso, estoy iniciando una aplicación de reproducción de medios), permitir que se ejecute y verificar que no se haya bloqueado. Por ejemplo, verifique si el PID todavía está activo, y luego reinicie el proceso, si ha muerto.Java ProcessBuilder: El proceso resultante se bloquea

El problema que estoy recibiendo ahora es que el PID permanece vivo en el sistema, pero la GUI de la aplicación se cuelga. Traté de cambiar el ProcessBuilder (cmd) .start() en un hilo separado, pero eso no parece resolver nada, como esperaba que fuera.

Básicamente el resultado es que, para el usuario, el programa APARECE que se ha bloqueado, pero matar el proceso de Java que impulsa el Proceso ProcessBuilder.start() realmente permite que el Proceso creado reanude su comportamiento normal. Esto significa que algo en la aplicación Java está interfiriendo con el Proceso engendrado, pero no tengo ni idea de qué, en este momento. (Por lo tanto, por qué traté de separarlo en otro hilo, que no parecía resolver nada)

Si alguien tiene alguna opinión/pensamientos, hágamelo saber, ya que no puedo, por la vida de mi pensar en cómo para resolver este problema.

Editar: No me preocupa el flujo de E/S creado a partir del Proceso, y por lo tanto no he tomado medidas para solucionarlo, ¿podría esto provocar un bloqueo en el Proceso mismo?

+3

Como ya ha indicado que no está tratando con las secuencias del proceso, debo decir que "Sí, es muy probable que sea la causa del problema. Es importante leer el contenido de stdout y stderr, y también escribe en stdin si el niño espera que lo haga ". Valdría la pena comprobar esta pregunta ASÍ: http://stackoverflow.com/questions/882772/capturing-stdout-when-calling-runtime-exec/882795#882795 –

Respuesta

30

Si el proceso escribe en stderr o stdout, y no lo está leyendo, simplemente se "bloqueará" y se bloqueará al escribir en stdout/err. O bien redirigir stdout/err a/dev/null usando una concha o fusionar stdout/err con redirectErrorStream (verdadero) y generar otro hilo que lee de salida estándar del proceso

+5

¡Extremadamente importante parece!TIENE QUE CONSUMIR el stdout/stderr de ffmpeg. Al menos lo noté para publicar/consumir conexiones de rtmp. – Nicholi

2

Editar: No me preocupa la secuencia de E/S creada a partir del proceso y, por lo tanto, no he tomado ninguna medida al respecto, ¿podría esto provocar un bloqueo en el proceso?

Si no lee los flujos de salida creados por el proceso, entonces es posible que la aplicación se bloquee una vez que los búferes de la aplicación estén llenos. Nunca he visto que esto ocurra en Linux (aunque no estoy diciendo que no lo haga), pero he visto este problema exacto en Windows. Creo que esto probablemente esté relacionado.

11

¿Quieres el truco?

No inicie su proceso desde ProcessBuilder.start(). No trate de meterse con la redirección/consumo de corriente de Java (sobre todo si se le da ninguna s ** t en ello;)

Uso ProcessBuilder.start() para iniciar un pequeño script de shell que se traga toda la entrada/flujos de salida.

Algo así:

#!/bin/bash 

nohup $1 >/dev/null 2>error.log & 

Es decir: si no se preocupan por la salida estándar y todavía desea iniciar sesión stderr (¿verdad?) A un archivo (error.log aquí).

Si ni siquiera se preocupan por stderr, simplemente redirigir la salida estándar:

#!/bin/bash 

nohup $1 >/dev/null 2>1 & 

Y se llama a ese pequeño script desde Java, dando como argumento el nombre del proceso que desea ejecutar .

Si un proceso que se ejecuta en Linux que está redirigiendo stdout y stderr a/dev/null siguen produciendo nada entonces usted tiene un roto, no conforme, instalar Linux;)

En otras palabras : el anterior Just Works [TM] y deshacerse de la problemática "necesita consumir las transmisiones en este y aquel orden bla bla bla No tiene sentido específico de Java".

+0

se rieron de nosotros, ahora es viernes por la noche y esto nos costó la noche :) –

5

Acabo de tropezar con esto después de que tuve un problema similar. De acuerdo con nos, necesita manejar la salida. Tenía algo como esto:

ProcessBuilder myProc2 = new ProcessBuilder(command); 
final Process process = myProc2.start(); 

y estaba funcionando genial. El proceso generado incluso dio como resultado alguna salida pero no mucho. Cuando comencé a producir mucho más, parecía que mi proceso ni siquiera se iniciaba más. Lo actualicé a esto:

ProcessBuilder myProc2 = new ProcessBuilder(command); 
myProc2.redirectErrorStream(true);   
final Process process = myProc2.start(); 
InputStream myIS = process.getInputStream(); 
String tempOut = convertStreamToStr(myIS); 

y comenzó a funcionar de nuevo. (consulte este enlace para el código convertStreamToStr(): http://singztechmusings.wordpress.com/2011/06/21/getting-started-with-javas-processbuilder-a-sample-utility-class-to-interact-with-linux-from-java-program/)

11

El subproceso que ejecuta el proceso puede bloquearse si no controla la salida. Esto se puede hacer generando un nuevo hilo que lea la salida del proceso.

final ProcessBuilder builder = new ProcessBuilder("script") 
        .redirectErrorStream(true) 
        .directory(workDirectory); 

    final Process process = builder.start(); 
    final StringWriter writer = new StringWriter(); 

    new Thread(new Runnable() { 
     public void run() { 
      IOUtils.copy(process.getInputStream(), writer); 
     } 
    }).start(); 

    final int exitValue = process.waitFor(); 
    final String processOutput = writer.toString(); 
+0

El hilo no parece terminar – user1120007

0

En caso de que necesite para capturar stdout y stderr y supervisar el proceso a continuación, utilizando Apache Commons Exec me ayudó mucho.

0

Creo que el problema es la tubería de almacenamiento en búfer de Linux.

intenta utilizar stdbuf con su ejecutable

new ProcessBuilder().command("/usr/bin/stdbuf","-o0","*executable*","*arguments*");** 

El -o0 dice no para amortiguar la salida. Lo mismo pasa con -i0 y -e0 si quiere desvincular la entrada y el canal de error.

Cuestiones relacionadas