Блоки ввода-вывода Java IO при чтении стандартного вывода и стандартной ошибки внешней программы на Си - PullRequest
4 голосов
/ 09 июля 2009

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

Прочитав ответы на этот похожий вопрос,

Чтение блокировки Java InputStream (особенно ответ от 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);</p>

<pre><code>    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);
        }
</code>

... </p> <p> public class EGMStreamGobbler implements Runnable{</p> 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: если кто-то может предложить аналогичную проблему с решением, это мне очень поможет!

Ответы [ 4 ]

8 голосов
/ 09 июля 2009

вместо

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 голосов
/ 09 июля 2009
  1. Если вы просто вызовете #run () для запускаемого объекта, он не будет выполняться параллельно. Чтобы запустить его параллельно, вам нужно создать java.lang.Thread, который выполняет #run () вашего Runnable.
  2. Зависит ли блокировка потока от обеих сторон потока. Если отправитель не отправляет какие-либо данные или получатель не получает данные, возникает ситуация блокировки. Если процессор должен что-то сделать, пока поток заблокирован, вам нужно порождать (другой) поток внутри процессора, чтобы ожидать новые данные и прерывать альтернативный процесс при передаче новых данных.
1 голос
/ 09 июля 2009

Не поэтому ли был создан nio?

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

1 голос
/ 09 июля 2009

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

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

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

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

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

...