ProcessStartInfo 挂在“WaitForExit"上?为什么? [英] ProcessStartInfo hanging on "WaitForExit"? Why?
问题描述
我有以下代码:
info = new System.Diagnostics.ProcessStartInfo("TheProgram.exe", String.Join(" ", args));
info.CreateNoWindow = true;
info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
System.Diagnostics.Process p = System.Diagnostics.Process.Start(info);
p.WaitForExit();
Console.WriteLine(p.StandardOutput.ReadToEnd()); //need the StandardOutput contents
我知道我正在启动的进程的输出大约有 7MB 长.在 Windows 控制台中运行它可以正常工作.不幸的是,这以编程方式在 WaitForExit
处无限期挂起.另请注意,对于较小的输出(例如 3KB),此代码不会挂起.
I know that the output from the process I am starting is around 7MB long. Running it in the Windows console works fine. Unfortunately programmatically this hangs indefinitely at WaitForExit
. Note also this code does NOT hang for smaller outputs (like 3KB).
ProcessStartInfo
中的内部 StandardOutput
是否有可能无法缓冲 7MB?如果是这样,我应该怎么做?如果没有,我做错了什么?
Is it possible that the internal StandardOutput
in ProcessStartInfo
can't buffer 7MB? If so, what should I do instead? If not, what am I doing wrong?
推荐答案
问题在于,如果您重定向 StandardOutput
和/或 StandardError
,内部缓冲区可能会变满.无论您使用什么顺序,都可能出现问题:
The problem is that if you redirect StandardOutput
and/or StandardError
the internal buffer can become full. Whatever order you use, there can be a problem:
- 如果在读取
StandardOutput
之前等待进程退出,进程可能会阻止尝试写入,因此进程永远不会结束. - 如果您使用 ReadToEnd 从
StandardOutput
中读取数据,那么如果进程从不关闭StandardOutput
(例如,如果它从不终止,则您的进程可能会阻塞,或者如果它被阻止写入StandardError
).
- If you wait for the process to exit before reading
StandardOutput
the process can block trying to write to it, so the process never ends. - If you read from
StandardOutput
using ReadToEnd then your process can block if the process never closesStandardOutput
(for example if it never terminates, or if it is blocked writing toStandardError
).
解决方案是使用异步读取来确保缓冲区不会变满.为了避免任何死锁并收集 StandardOutput
和 StandardError
的所有输出,您可以这样做:
The solution is to use asynchronous reads to ensure that the buffer doesn't get full. To avoid any deadlocks and collect up all output from both StandardOutput
and StandardError
you can do this:
如果超时发生,请参阅下面的答案以了解如何避免 ObjectDisposedException.
See answers below for how avoid an ObjectDisposedException if the timeout occurs.
using (Process process = new Process())
{
process.StartInfo.FileName = filename;
process.StartInfo.Arguments = arguments;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
StringBuilder output = new StringBuilder();
StringBuilder error = new StringBuilder();
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
{
process.OutputDataReceived += (sender, e) => {
if (e.Data == null)
{
outputWaitHandle.Set();
}
else
{
output.AppendLine(e.Data);
}
};
process.ErrorDataReceived += (sender, e) =>
{
if (e.Data == null)
{
errorWaitHandle.Set();
}
else
{
error.AppendLine(e.Data);
}
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
if (process.WaitForExit(timeout) &&
outputWaitHandle.WaitOne(timeout) &&
errorWaitHandle.WaitOne(timeout))
{
// Process completed. Check process.ExitCode here.
}
else
{
// Timed out.
}
}
}
这篇关于ProcessStartInfo 挂在“WaitForExit"上?为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!