c# - ProcessStartInfo 卡在 "WaitForExit"上?为什么?

标签 c# processstartinfo

我有以下代码:

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),此代码不会挂起。

有没有可能ProcessStartInfo中的内部StandardOutput缓冲不了7MB?如果是这样,我应该怎么做?如果不是,我做错了什么?

最佳答案

问题是,如果您重定向 StandardOutput 和/或 StandardError,内部缓冲区可能会变满。无论您使用什么顺序,都可能存在问题:

  • 如果在读取 StandardOutput 之前等待进程退出,进程可能会阻止尝试写入它,因此进程永远不会结束。
  • 如果您使用 ReadToEnd 从 StandardOutput 读取数据,那么如果进程从未关闭 StandardOutput(例如,如果它从未终止,或者如果它被阻止写入 StandardError)。

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

编辑:请参阅下面的答案,了解如何在发生超时时避免 ObjectDisposedException

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.
        }
    }
}

关于c# - ProcessStartInfo 卡在 "WaitForExit"上?为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38339062/

相关文章:

c# - 使用 Process.Start : Firefox not starting when you set Usename and Password 启动 Firefox

c# - ConfigurationChangeWatcher.Poller()

c# - 在 C#、VS2008 中的 ComboBox 中隐藏箭头按钮

c# - ProcessStartInfo 卡在 "WaitForExit"上?为什么?

c# - 从控制台应用程序 (C#/WinForms) 发送输入/获取输出

c# - C# 中的交互式控制台 I/O 包装器/拦截器 - 问题是什么?

c# - 未为非基本语言选择正确的 Resx 文件

C# 设置 ListBox 宽度,使最长的项目适合

c# - DataTrigger 当大于一个数

c# - Win32Exception: 目录名无效