简体   繁体   English

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

[英]Concurrency issue between waiting for a process and reading the stream?

I use a ProcessBuilder to run processes. 我使用ProcessBuilder来运行进程。 I handle Input/Output streams by submitting the corresponding runnables handling them in a thread pool ( Executors.newCachedThreadPool() ). 我通过提交在线程池( Executors.newCachedThreadPool() )中处理它们的相应runnable来处理输入/输出流。
I get the result but every now and then I don't get anything. 我得到了结果但是偶尔我什么也得不到。
For instance if I do: cmd \\C dir to the process builder I get the results of dir back but sometimes I don't get anything (despite that the result seems to comeback from the runnable that handles the process.getInputStream ). 例如,如果我执行: cmd \\C dir到进程构建器,我得到dir的结果,但有时我没有得到任何东西(尽管结果似乎从处理process.getInputStream的runnable回来)。
How can I debug this? 我该怎么调试呢? It shows up intermitently. 它间歇地出现了。 With the same code I did not have any problem when I did new Thread(runnable).start() . 使用相同的代码,当我执行new Thread(runnable).start()时,我没有任何问题。 It started to happen after I switched to a thread pool. 它在我切换到线程池后开始发生。

Update: 更新:
I think I found something: 我想我找到了些东西:
I do the following in the Runnable : 我在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){}  
}

In the cases that does not work it prints Finished reading 521 . 在不起作用的情况下,它打印Finished reading 521 But I try to get the result via the pw and not sb . 但我试图通过pw得到结果,而不是sb
pw is PrintWriter pw = PrintWriter(outputStream);` which I pass in the runnable pw是PrintWriter pw = PrintWriter(outputStream);`我在runnable中传递的

Update 2: 更新2:
It seems that: status = process.waitFor(); 看来: status = process.waitFor(); returns earlier before the runnable that handled the inputstream finishes. 处理输入流的runnable完成之前返回。 How can this happen? 怎么会发生这种情况?
I read in the javadoc: 我在javadoc中读到:
the calling thread will be blocked until the subprocess exits . the calling thread will be blocked until the subprocess exits So does that mean that I could return before consuming the I/O streams? 那么这是否意味着我可以消耗I / O流之前返回?

Update 3: 更新3:
Seems to be the same issue here in Ruby Ruby中似乎是同样的问题
Ie there is some race condition between the process ending and consuming the output 过程结束和消耗输出之间存在一些竞争条件

Yes. 是。 stdio between processes is buffered (usually 4KB buffers). 进程之间的stdio是缓冲的(通常是4KB缓冲区)。 Process A write into the buffer and exist. 进程A写入缓冲区并存在。 Process B has two threads; 进程B有两个线程; one waits for the end of A and the other reads the output from A. There is no way to be sure which thread executes first. 一个等待A的结束而另一个从A读取输出。无法确定哪个线程首先执行。

So it's possible (even likely when there is a lot of output) that process.waitFor(); 因此有可能(甚至可能在有大量输出时) process.waitFor(); returns before all buffered output has been read. 在读取所有缓冲输出之前返回。

Note that flushing doesn't help here because it just makes sure that A has written everything. 请注意,刷新对此没有帮助,因为它只是确保A已写入所有内容。 There is no way to "force" B to read the data in a similar way. 没有办法“强制”B以类似的方式读取数据。

Therefore, you should remember the exit status and consider the process as "fully terminated" only when you read EOF from the input stream. 因此,只有在从输入流中读取EOF时,才应记住退出状态并将该过程视为“完全终止”。

EDIT One solution would be to move the waitFor() into the stream gobbler and convert the gobbler into a Callable which you could then submit to the executor and use the Future API ( example ) to get the result(s). 编辑一个解决方案是将waitFor()移动到流gobbler并将gobbler转换为Callable ,然后您可以将其提交给执行程序并使用Future API( 示例 )来获取结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM