java - example - Process.waitFor(), threads y InputStreams
getinputstream java ejemplo (2)
En pseudocódigo, esto es lo que estoy haciendo:
Process proc = runtime.exec(command);
processOutputStreamInThread(proc.getInputStream());
processOutputStreamInThread(proc.getErrorStream());
proc.waitFor()
Sin embargo, a veces processOutputStreamInThread
no ve ningún resultado y, a veces lo hace. A grandes rasgos, el método crea un BufferedInputStream
de la salida del comando y lo envía a un registrador.
Según lo que estoy viendo, supongo que el command
no necesita tener toda su salida en las secuencias alimentadas por getInputStream()
y getErrorStream()
, lo que permite que la secuencia esté vacía.
Los resultados de mis ensayos son las siguientes preguntas:
(1) ¿ waitFor()
en java.lang.Process requiere que la salida del programa ejecutado se haya leído antes de que vuelva?
La documentación solo establece:
hace que el hilo actual espere, si es necesario, hasta que finalice el proceso representado por este objeto
Process
. Este método regresa inmediatamente si el subproceso ya ha finalizado. Si el subproceso aún no ha terminado, la cadena de llamada será bloqueada hasta que el subproceso finalice.
(2) ¿En qué condiciones las secuencias proporcionadas por getInputStream
y getErrorStream
deben cerrarse y / o se cierran automáticamente?
La documentación solo establece:
Obtiene la secuencia de error del subproceso. La secuencia obtiene datos transmitidos desde la secuencia de salida de error del proceso representado por este objeto de proceso.
Nota de implementación: es una buena idea que la corriente de entrada se almacene en un búfer.
Un usuario informa que tuvo que cerrar las transmisiones él mismo, pero recibo una excepción al menos una parte del tiempo que indica que la transmisión ya está cerrada cuando intento hacerlo.
Editar: cambió getOutputStream
a getInputStream
, ahora presente arriba.
Resolución: el problema terminó siendo que, en ciertos casos, los hilos utilizados para procesar el flujo de salida no se ejecutarían hasta después de que mi proceso de muy corta vida se hubiera completado, lo que daría como resultado que el flujo de entrada no me diera ningún dato. waitFor
no esperó la salida del programa ejecutado. Más bien, el programa se ejecutó y finalizó antes de que se pudiera recopilar cualquier resultado.
Utilicé subprocesos porque no estoy seguro de cuánta salida obtendría por error estándar y salida estándar y quería poder procesar ambos simultáneamente, sin bloquear uno u otro, solo uno de ellos debería tener datos disponibles. Pero, como mis hilos no pueden leer de forma consistente la salida del programa ejecutado, no es una solución.
Mi código final se veía algo como esto:
ProcessBuilder pb = new ProcessBuilder(cmdargs);
pb.redirectErrorStream(true);
Process proc = pb.start();
processOutputStream(proc.getInputStream());
proc.waitFor()
Creo que esto es un poco contrario a la intuición, pero:
getOutputStream Obtiene la secuencia de salida del subproceso. La salida a la corriente se canaliza a la corriente de entrada estándar del proceso representado por este objeto de proceso. Nota de implementación: es una buena idea que el flujo de salida se almacene en un búfer. Devuelve: el flujo de salida conectado a la entrada normal del subproceso.
Leí que, como este flujo de salida del proceso principal, se adjunta a la entrada estándar del subproceso, de modo que cuando escribe en getOutputStream (). Write () en realidad está escribiendo en el stdin.
¿Posiblemente quiera usar .getInputStream ()?
Devuelve: la corriente de entrada conectada a la salida normal del subproceso.
En cuanto a Process.Waitfor (), los documentos API dicen:
hace que el hilo actual espere, si es necesario, hasta que finalice el proceso representado por este objeto Proceso. Este método regresa inmediatamente si el subproceso ya ha finalizado. Si el subproceso aún no ha terminado, la cadena de llamada será bloqueada hasta que el subproceso finalice.
Yo diría que el subproceso en el que se llama se bloqueará hasta que el proceso finalice su ejecución. Es posible que aún esté procesando la salida en esta etapa dependiendo de los otros subprocesos o que hayan finalizado antes de que vuelva el subproceso.
Si su proceso externo espera algo en su stdin
, DEBE cerrar el getOutputStream
. De lo contrario, waitFor
para siempre.
Aquí está el When Runtime.exec () no será artículo de JavaWorld que describa las diferentes trampas del método exec y cómo evitarlas.
Desde mi experiencia, es mejor consumir STDOUT y STDERR del proceso secundario (hasta EOF) y luego bloquear en waitFor
. Esperemos que en este momento no tenga que esperar por mucho tiempo.
Una respuesta a la pregunta de Kaleb. En condiciones normales, no debe cerrar las transmisiones, sin embargo, debido a que está waitingFor
Por alguna razón, no tiene un tiempo de espera, es posible que deba cerrar estas transmisiones si encuentra algunas condiciones de error en la salida y no desea procesar salida del niño más allá. Sin embargo, si el programa secundario terminará (bloqueará) cuando esté cerrado STDOUT o STDERR se cerrará en el otro extremo, estará totalmente a la altura de la implementación de ese niño. Sin embargo, la mayoría de los programas de shell terminarán bajo tales condiciones.
Realmente deseo waitFor
tuve un tiempo de espera significativo y el Process
tuvo una forma documentada de limpiar sus recursos cuando decidió abandonar su monitoreo.