ProcessStartInfo 挂在“WaitForExit"上?为什么? [英] ProcessStartInfo hanging on "WaitForExit"? Why?

查看:23
本文介绍了ProcessStartInfo 挂在“WaitForExit"上?为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

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 closes StandardOutput (for example if it never terminates, or if it is blocked writing to StandardError).

解决方案是使用异步读取来确保缓冲区不会变满.为了避免任何死锁并收集 StandardOutputStandardError 的所有输出,您可以这样做:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆