Visualizzazione dei risultati da 1 a 7 su 7
  1. #1

    Swing e processo esterno.

    Salve a tutti,
    ho scritto un'applicazione che usa Swing per la gui ed in modo periodico deve invocare un processo esterno eseguendo un .exe che genera dei file che devono essere inviati ad un server remoto.
    Tutto questo processo della generazione dei file e del loro upload al server non interferisce minimamente con la gui che continua a lavorare per conto suo nell'EDT di Swing.
    Per implementare questo sistema non ho quindi utilizzato gli oggetti di Swing per eseguire l'upload dei files in un altro thread come SwingUtilities.invokeLater o SwingWorker e sincronizzare il tutto con l'EDT, visto che questo processo che genera ed invia i files al server non interferisce minimamente con ciò che viene mostrato nella gui.
    Ho semplicemente provveduto a creare un nuovo Thread a cui ho passato un oggetto Runnable nel cui metodo run() ho fatto tutto.
    Poi ho settato questo thread come daemon thread e l'ho avviato con start().
    Tutto quì.
    Volevo solo una conferma di aver seguito la strada giusta nel non utilizzare affatto gli oggetti di Swing per gestire l'altro thread.
    Per invocare l'eseguibile esterno ho ovviamente utilizzato l'oggetto Runtime di java con un normale Runtime.exec(...) all'interno del metodo run() del Runnable passato al Thread.
    Grazie in anticipo!
    Ultima modifica di Samaritan; 05-04-2014 a 15:34

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da Samaritan Visualizza il messaggio
    non ho quindi utilizzato gli oggetti di Swing per eseguire l'upload dei files in un altro thread come SwingUtilities.invokeLater o SwingWorker e sincronizzare il tutto con l'EDT
    invokeLater non sarebbe stato comunque utile nel tuo caso. invokeLater fa eseguire qualcosa "appena possibile" ma comunque nel contesto del EDT.
    SwingWorker invece fa eseguire quel qualcosa in un thread separato ma facilita la interazione con la GUI (nel EDT) nel caso il "lavoro" debba fare, di tanto in tanto, qualche aggiornamento sulla interfaccia utente.

    Quote Originariamente inviata da Samaritan Visualizza il messaggio
    visto che questo processo che genera ed invia i files al server non interferisce minimamente con ciò che viene mostrato nella gui.
    Ho semplicemente provveduto a creare un nuovo Thread a cui ho passato un oggetto Runnable nel cui metodo run() ho fatto tutto.
    Poi ho settato questo thread come daemon thread e l'ho avviato con start().

    Per invocare l'eseguibile esterno ho ovviamente utilizzato l'oggetto Runtime di java con un normale Runtime.exec(...) all'interno del metodo run() del Runnable passato al Thread.
    Corretto sì, lo è. Si potrebbe far notare una cosa però. Il exec() avvia il processo in modo asincrono, ovvero exec è praticamente immediato. Se non devi attendere la fine del processo per prendere il suo exit-code e non devi fornire al processo dati continui su standard-input oppure leggere i suoi standard-output/error, allora il nuovo thread a parte non servirebbe nemmeno tanto.

    Detto però meglio in generale: se il processo lanciato scrive molto su standard-output/error allora tale output deve essere letto lato Java, altrimenti il processo può bloccarsi (questioni di buffering). Quindi un thread a parte ci vorrebbe veramente.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    Quote Originariamente inviata da andbin Visualizza il messaggio
    Corretto sì, lo è. Si potrebbe far notare una cosa però. Il exec() avvia il processo in modo asincrono, ovvero exec è praticamente immediato. Se non devi attendere la fine del processo per prendere il suo exit-code e non devi fornire al processo dati continui su standard-input oppure leggere i suoi standard-output/error, allora il nuovo thread a parte non servirebbe nemmeno tanto.

    Detto però meglio in generale: se il processo lanciato scrive molto su standard-output/error allora tale output deve essere letto lato Java, altrimenti il processo può bloccarsi (questioni di buffering). Quindi un thread a parte ci vorrebbe veramente.
    Ti ringrazio molto per la completezza della tua risposta perché oltre a darmi una utile conferma di quanto ho fatto, mi hai anche tolto un dubbio che avevo e non avevo proprio esposto e cioè se la lettura degli InputStream dell'oggeto Process fosse una opzione oppure un obbligo.
    Siccome il contenuto di questo stream non mi interessa più di tanto e neppure il suo exitCode, visto che se in un ciclo dovesse esserci qualche problema non conterebbe più di tanto, poiché questi cicli di generazione/invio dei files avvengono ogni 30 secondi.
    Da quello che mi hai scritto invece sembra essere molto importante che io legga di volta in volta questo InputStream del processo(anche se non mi interessa il suo contenuto), gestendo tutto in un try-catch con un finally che provvederebbe di volta in volta a garantire la chiusura dello stream stesso.
    Attualmente ho aggiunto questo thread aggiuntivo all'edt soltanto per fare in modo che si instaurasse un contesto concorrente tra l'edt ed il processo di invio dei files che può richiedere diversi secondi per concludersi.
    Ma se tu mi scrivi che già internamente l'utilizzo di Runtime.exec crea di suo un nuovo thread, allora mi pare di capire che questo nuovo thread che ho aggiunto per non influenzare l'edt sia praticamente inutile per questo scopo.
    Quindi l'unica causa plausibile che ogni tanto ha causato dei veri e propri dead-locks dell'applicativo non può che risiedere nella saturazione del buffer utilizzato dalla jvm per salvare l'output del processo.
    Mi confermi quindi che è fondamentale che io legga l'inputstream e l'errorstream del processo e provveda sempre a chiudere questi stream ad ogni ciclo di invocazione dell'eseguibile esterno in modo da liberare tutte le risorse utilizzate da questi stream del processo e scongiurare il rischio di dead-lock del'applicativo?
    Confermo che l'acquisizione dei due stream del processo che recentemente avevo pensato di escludere era già stata fatta in un altro suo thread specifico che provvedeva a leggerne il contenuto e che chiudeva gli stream alla fine.
    Inoltre il processo non richiede l'invio continuo di dati e non manda neppure uno stream lungo che richiede grossi buffer per potere essere memorizzato e letto.
    E' semplicemente un eseguibile che rimane sempre attivo e non si conclude mai.
    Per questo non sono potuto rimanere in attesa del suo exitCode e neppure fare un join sul thread che ne gestisce l'inputstream e l'errorstream per mettere in attesa il current-thread fino a quando tali stream si concludevano.
    Proprio perché non c'è alcuna uscita del processo stesso ed a Swing interessa soltanto che questo processo venga avviato e che inizi a generare periodicamente questi files ogni 30 secondi.
    Swing non deve fare altro che eseguire questo processo esterno una sola volta all'avvio e poi reinviare tali files ogni 30 secondi.
    La fase di invio dei file al server remoto è ovviamente la cosa più dispendiosa in termini di tempo ed è per questo che avevo pensato di creare un altro thread che la gestisse.
    Forse ora mi sono spiegato meglio sul sistema.
    Grazie di nuovo.
    Ultima modifica di Samaritan; 05-04-2014 a 17:55

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da Samaritan Visualizza il messaggio
    se la lettura degli InputStream dell'oggeto Process fosse una opzione oppure un obbligo.
    Proprio "obbligo" no. Nel senso che se tu sai che il processo non fa assolutamente output o se di per sé può farne ma l'hai avviato con una qualche sua opzione che lo rende "quiet" (silenzioso) .... allora non è veramente necessario leggere gli stream di Process.

    Quote Originariamente inviata da Samaritan Visualizza il messaggio
    Ma se tu mi scrivi che già internamente l'utilizzo di Runtime.exec crea di suo un nuovo thread
    exec non crea alcun thread! Semplicemente la richiesta al sistema di avviare un nuovo processo è una cosa che richiede frazioni di un secondo .... non secondi o minuti.

    Quote Originariamente inviata da Samaritan Visualizza il messaggio
    Mi confermi quindi che è fondamentale che io legga l'inputstream e l'errorstream del processo e provveda sempre a chiudere questi stream ad ogni ciclo di invocazione dell'eseguibile esterno in modo da liberare tutte le risorse utilizzate da questi stream del processo e scongiurare il rischio di dead-lock del'applicativo?
    Se il processo fa "abbastanza" output su standard-output e/o standard-error, ripeto che gli stream di Process vanno letti.
    Per sapere se il processo fa dell'output, documentati se ha una documentazione o comunque provalo "a mano" da una console.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  5. #5
    Quote Originariamente inviata da andbin Visualizza il messaggio
    Proprio "obbligo" no. Nel senso che se tu sai che il processo non fa assolutamente output o se di per sé può farne ma l'hai avviato con una qualche sua opzione che lo rende "quiet" (silenzioso) .... allora non è veramente necessario leggere gli stream di Process.


    exec non crea alcun thread! Semplicemente la richiesta al sistema di avviare un nuovo processo è una cosa che richiede frazioni di un secondo .... non secondi o minuti.


    Se il processo fa "abbastanza" output su standard-output e/o standard-error, ripeto che gli stream di Process vanno letti.
    Per sapere se il processo fa dell'output, documentati se ha una documentazione o comunque provalo "a mano" da una console.
    Ah perfetto, allora non è stato inutile utilizzare Process in un nuovo thread perché anche se come tu scrivi, la richiesta al sistema di avviare un nuovo processo è una cosa che richiede istanti, nel mio caso il processo esterno che viene eseguito è un processo pesantissimo che fa delle elaborazioni complicatissime su segnali in arrivo da un radar x-band collegato al pc tramite una scheda proprietaria di acquisizione.
    Capirai quindi che quel exec se viene eseguito nell'edt può realmente creare seri problemi o addirittura blocchi nella gui stessa se qualcosa non dovesse andare correttamente e comunque essendo un processo che non esce, ma resta in uno stato di elaborazione continua, credo che se non viene gestito in un altro thread non può che appesantire l'edt che si rallenterebbe o diventerebbe instabile.
    In poche parole se invoco Runtime.exec senza farlo nel run di un nuovo Thread, per forza di cose quell'oggetto Process viene gestito nell'unico thread dell'edt e questo non credo sia la soluzione corretta considerando che l'eseguibile avviato dall'exec è molto pesante e soprattutto non ritorna mai.
    Ultima modifica di Samaritan; 05-04-2014 a 23:22

  6. #6
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da Samaritan Visualizza il messaggio
    nel mio caso il processo esterno che viene eseguito è un processo pesantissimo che fa delle elaborazioni complicatissime su segnali in arrivo da un radar x-band collegato al pc tramite una scheda proprietaria di acquisizione.
    Questo non vuol dire assolutamente niente. Qui non centra cosa fa o usa il nuovo processo esterno.

    Quote Originariamente inviata da Samaritan Visualizza il messaggio
    Capirai quindi che quel exec se viene eseguito nell'edt può realmente creare seri problemi o addirittura blocchi nella gui stessa se qualcosa non dovesse andare correttamente
    Ripeto che exec() è generalmente quasi immediato. Non centra se quello che lanci è un super-mega-programma che fa chissà che cosa per chissà quanto tempo ....

    Quote Originariamente inviata da Samaritan Visualizza il messaggio
    e comunque essendo un processo che non esce, ma resta in uno stato di elaborazione continua, credo che se non viene gestito in un altro thread non può che appesantire l'edt che si rallenterebbe o diventerebbe instabile.
    Se devi aspettare il suo exit-code e/o gestire i suoi stream, sì, ovviamente questo non va fatto nel EDT.

    Quote Originariamente inviata da Samaritan Visualizza il messaggio
    In poche parole se invoco Runtime.exec senza farlo nel run di un nuovo Thread, per forza di cose quell'oggetto Process viene gestito nell'unico thread dell'edt
    Te lo ripeto ancora una volta: exec() è veloce, non è certo questo che bloccherebbe in modo grave il EDT.
    Sui sistemi Windows il exec() è sicuramente veloce, ne ho già avuto prova diverse volte. Sui sistemi Unix-like il concetto di "spawn" di un nuovo processo è un po' diverso rispetto ai Windows, quindi ci sono altre cose da considerare ma non credo, onestamente, che si possa parlare di "secondi" .... molto meno.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  7. #7
    Ah ecco, quindi in generale se invoco exec senza usare un nuovo thread, l'edt viene rallentato se e solo se oltre ad invocare exec mi metto ad attendere l'exitCode del processo tramite un waitFor().
    Anzi nel mio caso si bloccherebbe proprio, visto che il mio processo non si conclude mai.
    Se invece invoco soltanto l'exec direttamente da swing senza usare un nuovo thread e sono certo che non ci sono stream in arrivo dal processo, posso stare tranquillo che il processo verrà fatto girare dal sistema operativo e quindi in modo totalmente indipendente dall'edt della jvm.
    E' chiaro che nel mio caso, essendo un processo che rimane sempre in esecuzione, non posso fare un waitFor() perché non ci sarà mai un exitCode restituito da questo metodo di Process.
    Comunque io per scongiurare qualsiasi problema sulla gui, ho creato un nuovo thread per l'invocazione di exec ed anche se come tu scrivi potrebbe non servire, credo che male non possa fare.
    Semplicemente ci sarebbe questo unico nuovo thread che si aggiungerebbe all'edt e che provvederebbe ad eseguire il processo esterno e si concluderebbe dopo aver letto e chiuso gli stream del processo stesso, lasciandolo avviato.
    Tra l'altro ho verificato tramite il prompt dei comandi e l'avvio del processo non genera proprio alcuno stream, almeno non nel prompt dei comandi e si vede soltanto l'icona corrispondente all'ambiente del processo che ha un suo runtime installato che è necessario per farlo girare.
    Ultima modifica di Samaritan; 06-04-2014 a 14:16

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.