2009-07-09 7 views
4

J'ai posté la même question ici il y a quelques jours (Java reading standard output from an external program using inputstream), et j'ai trouvé d'excellents conseils pour traiter un bloc en cours de lecture (while (is.read())! = -1)), mais je n'arrive toujours pas à résoudre le problème.Java IO entréestream bloque en lisant la sortie standard et l'erreur standard d'un programme externe C

Après avoir lu les réponses à cette question similaire,

Java InputStream blocking read (esp, la réponse Posté par Guss),

Je commence à croire que le bouclage d'un flux d'entrée en utilisant is.read() La condition! = -1 ne fonctionne pas si le programme est interactif (c'est-à-dire qu'il prend plusieurs entrées de l'utilisateur et présente des sorties supplémentaires sur les entrées suivantes, et le programme ne sort que lorsqu'une commande de sortie explicite est donnée). J'avoue que je ne connais pas grand-chose du multithread, mais je pense que j'ai besoin d'un mécanisme pour suspendre rapidement les threads du flux d'entrée (un pour stdout, stderr) quand une entrée utilisateur est nécessaire, et reprendre une fois l'entrée fourni pour empêcher un blocage. Ce qui suit est mon code actuel qui connaît un bloc sur la ligne indiquée:

 
EGMProcess egm = new EGMProcess(new String[]{directory + "/egm", "-o", 
       "CasinoA", "-v", "VendorA", "-s", "localhost:8080/gls/MessageRobot.action ", 
       "-E", "glss_env_cert.pem", "-S", "glss_sig_cert.pem", "-C", "glsc_sig_cert.pem", 
       "-d", "config", "-L", "config/log.txt", "-H", "GLSA-SampleHost"}, new String[]{"PATH=${PATH}"}, directory);

egm.execute(); 

    BufferedReader stdout = new BufferedReader(new InputStreamReader(egm.getInputStream())); 
    BufferedReader stderr = new BufferedReader(new InputStreamReader(egm.getErrorStream())); 

    EGMStreamGobbler stdoutprocessor = new EGMStreamGobbler(stdout, egm); 
    EGMStreamGobbler stderrprocessor = new EGMStreamGobbler(stderr, egm); 

    BufferedWriter stdin = new BufferedWriter(new OutputStreamWriter(egm.getOutputStream())); 


    stderrprocessor.run(); //<-- the block occurs here! 
    stdoutprocessor.run(); 


    //EGM/Agent test cases 


     //check bootstrap menu 
     if(!checkSimpleResult("******** EGM Bootstrap Menu **********", egm)) 
     { 
      String stdoutdump = egm.getStdOut(); 
      egm.cleanup(); 
      throw new Exception("can't find '******** EGM Bootstrap Menu **********'" + 
       "in the stdout" + "\nStandard Output Dump:\n" + stdoutdump); 
     } 

     //select bootstrap 
     stdin.write("1".toCharArray()); 
     stdin.flush(); 

     if(!checkSimpleResult("Enter port to receive msgs pushed from server ('0' for no push support)", egm)){ 
      String stdoutdump = egm.getStdOut(); 
      egm.cleanup(); 
      throw new Exception("can't find 'Enter port to receive msgs pushed from server ('0' for no push support)'" + 
        "in the stdout" + "\nStandard Output Dump:\n" + stdoutdump); 
     } 

...

public class EGMStreamGobbler implements Runnable{

private BufferedReader instream; private EGMProcess egm; public EGMStreamGobbler(BufferedReader isr, EGMProcess aEGM) { instream = isr; egm = aEGM; } public void run() { try{ int c; while((c = instream.read()) != 1) { egm.processStdOutStream((char)c); } } catch(IOException e) { e.printStackTrace(); } }

}

Je présente mes excuses pour la longueur du code, mais mon les questions sont,

1) Y a-t-il un moyen de contrôler le processus de prise en intrants (stdout, stderr) sans utiliser read()? Ou est-ce que je ne fais qu'appliquer cela mal? 2) Le multithreading est-il la bonne stratégie pour développer le processus de saisie des flux d'entrée et d'écriture d'une sortie? PS: si quelqu'un peut fournir un problème similaire avec la solution, cela m'aidera beaucoup!

Répondre

8

au lieu de

stderrprocessor.run(); //<-- the block occurs here! 
stdoutprocessor.run(); 

Vous devez commencer les discussions:

Thread errThread = new Thread(stderrprocessor); 
errThread.setDaemon(true); 
errThread.start(); 

Thread outThread = new Thread(stdoutprocessor); 
outThread.setDaemon(true); 
outThread.start(); 

run() est juste une méthode décrite dans Runnable. Thread.start() appelle run() sur le Runnable dans un nouveau Thread.

2
  1. Si vous appelez simplement #run() sur un runnable, il ne sera pas exécuté en parallèle. Pour l'exécuter en parallèle, vous devez générer un java.lang.Thread, qui exécute le #run() de votre Runnable.
  2. Le blocage d'un flux dépend des deux côtés du flux. Si l'expéditeur n'envoie aucune donnée ou si le destinataire ne reçoit pas de données, vous avez une situation de blocage. Si le processeur doit faire quelque chose, alors que le flux est bloqué, vous devez générer un thread (autre) dans le processeur pour attendre de nouvelles données et interrompre le processus alternatif, lorsque de nouvelles données sont diffusées.
1

D'abord, vous devez lire sur Thread et Runnable. Vous n'appelez pas Runnable.run() directement, vous configurez Threads pour cela et démarrez les threads.

Mais le plus important, la présence de trois threads indépendants implique la nécessité d'une conception soignée. Pourquoi 3 threads? Les deux que vous venez de commencer, et le principal.

Je suppose que l'idée générale de votre application est d'attendre l'arrivée d'une sortie, de l'interpréter et, par conséquent, d'envoyer une commande à l'application que vous contrôlez?

Votre thread principal doit donc attendre que l'un des threads du lecteur dise: «Ah, c'est intéressant, mieux vaut demander à l'utilisateur ce qu'il veut faire». En d'autres termes, vous avez besoin d'un mécanisme de communication entre vos lecteurs et votre rédacteur. En d'autres termes, vous avez besoin d'un mécanisme de communication entre vos lecteurs et votre rédacteur. Ceci pourrait être implémenté en utilisant le mécanisme d'événement de Java. Encore plus de lecture, j'ai peur.

1

N'est-ce pas la raison pour laquelle le nio a été créé?

Je ne connais pas beaucoup les canaux de nio, mais this answer peut être utile. Il montre comment lire un fichier en utilisant nio. Peut être utile.