2010-07-19 4 views
28

Ho cercato di utilizzare ProcessBuilder di Java per avviare un'applicazione in Linux che dovrebbe essere eseguita "a lungo termine". Il modo in cui questo programma viene eseguito è quello di avviare un comando (in questo caso, sto lanciando un'applicazione di riproduzione multimediale), consentirne l'esecuzione e controllare che non si sia arrestato in modo anomalo. Ad esempio, controlla se il PID è ancora attivo, quindi riavvia il processo, se è morto.ProcessBuilder Java: blocchi di processo risultanti

Il problema che sto ottenendo in questo momento è che il PID rimane attivo nel sistema, ma la GUI per l'applicazione si blocca. Ho provato a spostare ProcessBuilder (cmd) .start() in un thread separato, ma questo non sembra risolvere nulla, come speravo sarebbe successo.

Fondamentalmente il risultato è che, per l'utente, il programma APPARE che si è arrestato in modo anomalo, ma l'abbattimento del processo Java che guida il processo ProcessBuilder.start() consente effettivamente al processo creato di riprendere il suo normale comportamento. Ciò significa che qualcosa nell'applicazione Java sta interferendo con il processo generato, ma non ho assolutamente idea di cosa, a questo punto. (Quindi perché ho provato a separarlo in un altro thread, che non sembra risolvere nulla)

Se qualcuno ha qualche input/pensieri, per favore fatemelo sapere, perché non posso per la vita di me pensare a come risolvere questo problema.

Modifica: non ho alcuna preoccupazione per il flusso I/O creato dal processo e non ho quindi adottato alcuna procedura per affrontarlo, potrebbe causare un blocco nel processo stesso?

+3

Dato che hai già affermato che non hai a che fare con i flussi del processo, devo dire che "Sì, è molto probabile che sia la causa del problema. È importante leggere il contenuto di stdout e stderr, e scrivi anche su stdin se il bambino si aspetta che tu ". Varrà la pena di controllare questa domanda SO: http://stackoverflow.com/questions/882772/capturing-stdout-when-calling-runtime-exec/882795#882795 –

risposta

30

Se il processo scrive su stderr o stdout e non lo stai leggendo, si bloccherà semplicemente, bloccandosi durante la scrittura su stdout/err. In entrambi i reindirizzare stdout/err a/dev/null utilizzando un guscio o unire stdout/err con redirectErrorStream (vero) e generare un altro thread che legge da stdout del processo

+5

Estremamente importante sembra!DOVETE CONSUMARE lo stdout/stderr da ffmpeg. Almeno me ne sono accorto per pubblicare/consumare connessioni rtmp. – Nicholi

2

Modifica: non ho alcun problema con il flusso I/O creato dal processo e non ho quindi adottato alcuna procedura per risolverlo, potrebbe causare un blocco nel processo stesso?

Se non si leggono i flussi di output creati dal processo, è possibile che l'applicazione si blocchi quando i buffer dell'applicazione sono pieni. Non l'ho mai visto accadere su Linux (anche se non sto dicendo che non lo sia) ma ho visto questo esatto problema su Windows. Penso che questo sia probabilmente correlato.

11

Volete il trucco?

Non avviare il processo da ProcessBuilder.start(). Non cercare di pasticciare con flusso di reindirizzamento/consumo da Java (soprattutto se si dà alcuna s ** t su di esso;)

Usa ProcessBuilder.start() per avviare un piccolo script di shell che divora tutti gli input/flussi di output.

Qualcosa del genere:

#!/bin/bash 

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

Cioè: se non si cura di stdout e ancora desidera accedere stderr (vero?) In un file (error.log qui).

Se non hai nemmeno preoccupate per stderr, solo reindirizzare stdout:

#!/bin/bash 

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

E si chiama quel piccolo script da Java, dando come argomento il nome del processo che si desidera eseguire .

Se un processo in esecuzione su Linux che sta riorientando sia stdout e stderr a/dev/null continuano a produrre nulla poi hai un rotto, non conforme, Linux installare;)

In altre parole : sopra Just Works [TM] e sbarazzarsi della problematica "è necessario consumare i flussi in questo e quell'ordine bla bla bla Java non-sense specifico".

+0

ci siamo fatti una bella risata - è venerdì sera e questo ci è costato la nostra serata :) –

5

Proprio imbattuti in questo dopo che ho avuto un problema simile. Accettando con i nos, è necessario gestire l'output. Ho avuto qualcosa di simile:

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

e funzionava benissimo. Il processo generato ha anche prodotto l'output dell'output ma non molto. Quando ho iniziato a produrre molto di più, sembrava che il mio processo non fosse stato ancora avviato. Ho aggiornato a questo:

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

e ha iniziato a funzionare di nuovo. (fare riferimento a questo collegamento per convertStreamToStr() codice: http://singztechmusings.wordpress.com/2011/06/21/getting-started-with-javas-processbuilder-a-sample-utility-class-to-interact-with-linux-from-java-program/)

11

Il thread che esegue il processo potrebbe bloccarsi se non gestisce l'output. Questo può essere fatto creando un nuovo thread che legge l'output del processo.

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

La discussione sembra non finire – user1120007

0

In caso di necessità di catturare stdout e stderr e monitorare il processo quindi utilizzando Apache Commons Exec mi ha aiutato molto.

0

Credo che il problema sia il pipe buffer da Linux stesso.

tenta di utilizzare stdbuf con il vostro eseguibile

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

Il -o0 dice di non tamponare l'uscita. Lo stesso vale per -i0 e -e0 se si desidera eliminare la pipe di input e di errore.