2009-07-09 4 views
4

Я написал один и тот же вопрос здесь несколько дней назад (Java reading standard output from an external program using inputstream), и я нашел несколько отличных советов при работе с блоком во время чтения (while (is.read())! = -1)), но я все еще не могу решить проблему.Блоки ввода-вывода Java IO при чтении стандартного вывода и стандартная ошибка внешней программы С

После прочтения ответов на этот подобный вопрос,

Java InputStream blocking read (особы, ответ Написал Guss),

Я начинаю верить в то, что зацикливание входного потока с помощью is.read() ! = -1 условие не работает, если программа является интерактивной (то есть, на последующих входах требуется несколько входных данных от пользователя и присутствующих дополнительных выходов, а программа выходит только тогда, когда дается явная команда выхода). Я признаю, что не много знаю о многопоточности, но я думаю, что мне нужен механизм, чтобы оперативно приостанавливать потоки потоков ввода (по одному для stdout, stderr), когда требуется ввод пользователя, и возобновлять работу после ввода для предотвращения блокировки. Ниже мой текущий код, который испытывает блок на линии указано:

 
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(); } }

}

Извиняюсь за длину кода, но мой вопросы:

1) Есть ли способ контролировать процесс ввода входных данных (stdout, stderr) без использования read()? Или я просто плохо это реализую?

2) Многопоточность правильной стратегии для разработки процесса ввода входных данных и записи вывода?

PS: если кто-то может предоставить аналогичную проблему с решением, это мне очень поможет!

ответ

8

вместо

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

Вы должны начать темы:

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

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

run() это просто метод, указанный в Runnable. Thread.start() звонки run() на Runnable в новом Thread.

2
  1. Если вы просто вызываете #run() на runnable, он не будет выполняться параллельно. Чтобы запустить его параллельно, вы должны создать java.lang.Thread, который выполняет #run() вашего Runnable.
  2. Независимо от того, зависит ли блок потока от обеих сторон потока. Если отправитель не отправляет какие-либо данные или получатель не получает данные, у вас есть ситуация с блоком. Если процессор должен что-то сделать, в то время как поток заблокирован, вам нужно создать поток (ноль) в процессоре, чтобы ждать новых данных и прервать альтернативный процесс при потоках новых данных.
1

Во-первых, вам необходимо прочитать «Thread and Runnable». Вы не вызываете Runnable.run() напрямую, вы настраиваете Threads для этого и запускаете потоки.

Но, что более важно, наличие трех независимых потоков подразумевает необходимость в каком-то тщательном проектировании. Почему 3 потока? Эти два вы только начали, а главное.

Я предполагаю, что общая идея вашего приложения состоит в том, чтобы дождаться появления некоторого вывода, интерпретировать его и в результате отправить команду управляющему приложению?

Итак, ваш основной поток должен подождать, пока один из потоков читателей скажет: «Ага! Интересно, лучше спросите пользователя, что он хочет делать».

Другими словами, вам нужен механизм связи между вашими читателями и вашим автором. Это может быть реализовано с использованием механизма событий Java. Еще боюсь, что читаю больше.

1

Не так ли было создано nio?

Я мало знаю о Каналах в nio, но this answer может быть вам полезен. Он показывает, как читать файл с помощью nio. Может быть полезно.