通过 C# 的 Process 类生成时,处理标准错误和程序输出的正确方法?

Posted

技术标签:

【中文标题】通过 C# 的 Process 类生成时,处理标准错误和程序输出的正确方法?【英文标题】:Correct way to handle standard error and output from a program when spawned via Process class from C#? 【发布时间】:2011-05-07 10:41:12 【问题描述】:

我阅读了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 内容。

那是正确的方法吗?

【问题讨论】:

查看答案***.com/a/7608823/276648 【参考方案1】:

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

在您的示例中,您正在阅读所有StandardError,然后是所有StandardOutput。如果子进程只向StandardError 和/或StandardOutput 写入少量数据,则此方法可以正常工作。如果子进程要向StandardOutput 写入大量数据,这是一个问题。当父进程等待消费来自StandardError 的数据时,子进程正忙于填满StandardOutput 缓冲区。

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

生成单独的线程并在每个线程上调用 ReadToEnd 在一个线程上使用 BeginReadEndReadProcess.ErrorDataReceivedProcess.OutputDataReceived 事件上添加处理程序,然后调用Process.BeginErrorReadLineProcess.BeginOutputReadLine

【讨论】:

【参考方案2】:

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

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

【讨论】:

是的,我很好奇你为什么不使用 MSDN You can use asynchronous read operations to avoid these dependencies and their deadlock potential. Alternately, you can avoid the deadlock condition by creating two threads and reading the output of each stream on a separate thread.中给出的这种方法 使用BeginOutputReadLine和OutputDataReceived在代码中编辑,您可以看看发布的代码是否正确? 这就是我最终得到的结果:bitbucket.org/lassevk/mercurial.net/src/728f85d67447/…

以上是关于通过 C# 的 Process 类生成时,处理标准错误和程序输出的正确方法?的主要内容,如果未能解决你的问题,请参考以下文章

c# 如何用using引入 process 类

在c#中如何使用process这个类来获取进程的详细信息

C# 方法通过字符串动态生成表单

C#使用Process类调用外部程序(转)

使用命名管道作为标准输入生成节点 child_process

TexturePacker 图集生成工具