Java ProcessBuilder: el proceso resultante se bloquea
linux crash (8)
Editar: no me preocupa la secuencia de E / S creada a partir del proceso y, por lo tanto, no he tomado ninguna medida para solucionarlo, ¿podría esto provocar un bloqueo en el proceso en sí mismo?
Si no lee los flujos de salida creados por el proceso, 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.
He intentado usar ProcessBuilder de Java 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.
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 parece haber fallado, 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. (De ahí que intenté separarlo en otro hilo, que no parecía resolver nada)
Si alguien tiene alguna opinión / pensamientos, por favor avíseme, ya que no puedo por mi propia vida pensar en cómo resolver este problema.
Editar: no me preocupa la secuencia de E / S creada a partir del proceso y, por lo tanto, no he tomado ninguna medida para solucionarlo, ¿podría esto provocar un bloqueo en el proceso en sí mismo?
¿Quieres el truco?
No inicie su proceso desde ProcessBuilder.start () . No intente meterse con el redireccionamiento / consumo de flujos de Java (especialmente si no proporciona ningún **;
Use ProcessBuilder.start () para iniciar un pequeño script de shell que engulle todas las secuencias de entrada / salida.
Algo como eso:
#!/bin/bash
nohup $1 >/dev/null 2>error.log &
Es decir: si no le importa stdout y aún desea registrar stderr (¿verdad?) En un archivo ( error.log aquí).
Si ni siquiera te importa stderr, solo redirígelo a stdout:
#!/bin/bash
nohup $1 >/dev/null 2>1 &
Y llama a esa pequeña secuencia de comandos de Java, dándole como argumento el nombre del proceso que desea ejecutar.
Si un proceso que se ejecuta en Linux y está redireccionando tanto stdout como stderr a / dev / null todavía produce algo, entonces tiene una instalación de Linux quebrada y no conforme;)
En otras palabras: el anterior Just Works [TM] y deshacerte de la problemática "necesitas consumir los flujos en este y en ese orden bla bla bla, no tiene sentido específico de Java" .
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 funcionó de maravilla. El proceso engendrado incluso produjo algo de salida, pero no mucho. Cuando comencé a producir mucho más, parecía que mi proceso ni siquiera se iniciaba más. Me 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. (refiérase a 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/ )
Creo que el problema es el conducto de almacenamiento en búfer de Linux.
Intenta usar stdbuf
con tu ejecutable
new ProcessBuilder().command("/usr/bin/stdbuf","-o0","*executable*","*arguments*");**
El -o0
dice no almacenar en búfer la salida. Lo mismo pasa con -i0
y -e0
si desea -e0
la entrada y el -e0
error.
El hilo que ejecuta el proceso puede bloquearse si no maneja 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();
En caso de que necesite capturar stdout y stderr y monitorear el proceso, usar Apache Commons Exec me ayudó mucho.
JDK7 tendrá soporte integrado para la redirección de E / S del subproceso:
http://download.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html
Mientras tanto, si realmente quieres descartar stdout / stderr, parece mejor (en Linux) invocar ProcessBuilder en un comando que se ve así:
["/bin/bash", "-c", "exec YOUR_COMMAND_HERE >/dev/null 2>&1"]
Si el proceso escribe en stderr o stdout, y no lo está leyendo, simplemente se "colgará" y se bloqueará al escribir en stdout / err. O redirigir stdout / err a / dev / null usando un shell o merge stdout / err con redirectErrorStream (true) y generar otro thread que lea desde stdout del proceso