【问题标题】:Java IO inputstream blocks while reading standard output & standard error of an external C programJava IO 输入流在读取外部 C 程序的标准输出和标准错误时阻塞
【发布时间】:2010-11-09 11:40:10
【问题描述】:

几天前我在这里发布了同样的问题(Java reading standard output from an external program using inputstream),我发现了一些很好的建议来处理阅读时的阻塞(while(is.read())!= -1)) ,但我仍然无法解决问题。

在阅读了这个类似问题的答案后,

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”}、新字符串[]{“PATH=${PATH}”}、目录);
    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);
        }

...

公共类 EGMStreamGobbler 实现 Runnable{

私有 BufferedReader 流内; 私有 EGMProcess egm; 公共 EGMStreamGobbler(BufferedReader isr,EGMProcess aEGM) { 流内 = isr; egm = 临时股东大会; } 公共无效运行() { 尝试{ 诠释 c; 而((c = instream.read()) != 1) { egm.processStdOutStream((char)c); } } 捕获(IOException e) { e.printStackTrace(); } }

}

对于代码的长度,我深表歉意,但我的问题是,

1) 有什么方法可以在不使用 read() 的情况下控制接收输入流(stdout、stderr)的过程?还是我执行得不好?

2) 多线程是开发接收输入流和编写输出过程的正确策略吗?

PS:如果有人能提供类似问题的解决方案,对我有很大帮助!

【问题讨论】:

    标签: java java-io


    【解决方案1】:

    而不是

    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()Runnable 上调用 run(),在一个新的 Thread 中。

    【讨论】:

      【解决方案2】:
      1. 如果你只是在一个可运行对象上调用#run(),它不会被并行执行。要并行运行它,您必须生成一个 java.lang.Thread,它会执行 Runnable 的 #run()。
      2. 流是否阻塞取决于流的两侧。如果发送方未发送任何数据或接收方未收到数据,则您处于阻塞状态。如果处理器必须做某事,而流被阻塞,您需要在处理器中生成一个(另一个)线程来等待新数据并在新数据流式传输时中断备用进程。

      【讨论】:

        【解决方案3】:

        首先,您需要阅读 Thread 和 Runnable。您不直接调用 Runnable.run(),而是设置线程来执行此操作,然后启动线程。

        但更重要的是,三个独立线程的存在意味着需要进行一些仔细的设计。为什么是3线程?你刚开始的两个,还有主要的。

        我假设你的应用程序的一般想法是等待一些输出到达,解释它,然后向你正在控制的应用程序发送命令?

        所以你的主线程需要等待其中一个读者线程说“啊哈!这很有趣,最好问问用户他想做什么。”

        换句话说,您需要一些读者和作者之间的沟通机制。 这可以使用 Java 的事件机制来实现。恐怕还要多读书。

        【讨论】:

          【解决方案4】:

          这不就是创建 nio 的原因吗?

          我对 nio 中的 Channels 了解不多,但 this answer 可能会有所帮助。它展示了如何使用 nio 读取文件。可能有用。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-07-26
            • 1970-01-01
            相关资源
            最近更新 更多