代码之家  ›  专栏  ›  技术社区  ›  Jim

等待进程和读取流之间的并发问题?

  •  7
  • Jim  · 技术社区  · 13 年前

    我使用 ProcessBuilder 以运行进程。我通过提交在线程池中处理输入/输出流的相应可运行文件来处理它们( Executors.newCachedThreadPool() ).
    我得到了结果,但时不时我什么都没得到。
    例如,如果我这样做: cmd \C dir 到流程生成器,我得到的结果 dir 回来了,但有时我什么都没得到(尽管如此,结果似乎从处理 process.getInputStream ).
    如何调试?它会无休止地出现。 使用相同的代码时,我没有遇到任何问题 new Thread(runnable).start() 。这是在我切换到线程池之后开始发生的。

    更新:
    我想我发现了一些东西:
    我在中执行以下操作 Runnable :

     try {  
        while ( (line = br.readLine()) != null) {  
                pw.println(line);  
                    sb.append(line);   
        }  
        System.out.println("Finished reading "+sb.length());  
    } catch (IOException e) {             
        e.printStackTrace();  
    }  
    finally{  
       pw.flush();     
      try{
        isr.close();  
      }catch(Exception e){}  
    }
    

    在不起作用的情况下,它会打印 Finished reading 521 。但我试图通过 pw 而不是 sb .
    压水 是PrintWriter pw=PrintWriter(outputStream);`我在跑道上通过的

    更新2:
    看起来: status = process.waitFor(); 提前返回 之前 处理输入流的可运行程序结束。这是怎么发生的?
    我在javadoc中读到:
    the calling thread will be blocked until the subprocess exits 那么这是否意味着我可以回来 之前 消耗I/O流?

    更新3:
    这里似乎也有同样的问题 Ruby
    即。 进程结束和消耗输出之间存在一些竞争条件

    1 回复  |  直到 13 年前
        1
  •  1
  •   Aaron Digulla    13 年前

    对进程之间的stdio是缓冲的(通常是4KB缓冲区)。进程A写入缓冲区并存在。进程B有两个线程;一个等待A的结束,另一个读取A的输出。无法确定哪个线程首先执行。

    因此,有可能(甚至可能在有大量输出的情况下) process.waitFor(); 在读取所有缓冲输出之前返回。

    请注意,冲洗在这里没有帮助,因为它只是确保A 书面的 每件事没有办法“强迫”B以类似的方式读取数据。

    因此,您应该记住退出状态,并且只有当您从输入流中读取EOF时,才将流程视为“完全终止”。

    编辑 一个解决方案是移动 waitFor() 转换为流吞噬程序,并将吞噬程序转换为 Callable 然后您可以将其提交给遗嘱执行人并使用 Future API( example )以获取结果。