7

我阅读了Process.StandardOutput的文档,其中包含以下引用:

如果父进程在 p.StandardOutput.ReadToEnd 之前调用 p.WaitForExit 并且子进程写入足够的文本来填充重定向的流,则可能导致死锁情况。

所以我想知道。如果我还担心在某些情况下可能会填充 StandardError,那么正确的方法是什么?

我是否必须使用循环来交替读取标准输出和错误,以避免填满,或者这个简单的代码是否足够:

string error = proc.StandardError.ReadToEnd();
string output = proc.StandardOutput.ReadToEnd();
bool didFinish = proc.WaitForExit(60000);

在发布了一些答案后进行了编辑

那么这是正确的方法吗?

var output = new StringBuilder();
proc.OutputDataReceived += (s, e) => output.Append(e.Data);
proc.BeginOutputReadLine();
string error = proc.StandardError.ReadToEnd();
bool didFinish = proc.WaitForExit(60000);

然后,仅当该过程实际完成时,我才使用 stringbuilder 内容。

那是正确的方法吗?

4

2 回答 2

7

您的示例代码可能会导致死锁情况,其中写入了一些内容StandardOutput而不是写入StandardError. 您链接的文档中的下一个示例也说明了这一点。

本质上,我建议的是在两个流上使用异步读取来填充缓冲区,因为流被写入,然后调用WaitForExit.

于 2010-11-09T19:03:11.860 回答
3

问题的出现是因为子进程将其标准输出和标准错误写入一对管道,操作系统为它们提供了一个有限的缓冲区。如果父母没有积极阅读他们两个,那么他们很可能会填满。当管道填满时,任何后续写入都会被阻止。

在您的示例中,您正在阅读所有StandardError然后所有StandardOutput. StandardError如果子进程只向和/或写入一点数据,这可以正常工作StandardOutput。如果子进程想要写入大量数据到StandardOutput. 当父进程等待从 消费数据时StandardError,子进程正忙于填满StandardOutput缓冲区。

最安全的方法是同时读取标准输入和标准错误。有几种方法可以做到这一点:

  • 产生单独的线程并ReadToEnd在每个线程上调用
  • 在一个线程上使用BeginReadEndRead
  • Process.ErrorDataReceived在and事件上添加处理程序Process.OutputDataReceived,然后调用Process.BeginErrorReadLineand Process.BeginOutputReadLine
于 2010-11-09T19:01:58.027 回答