ProcessStartInfo hanging on “WaitForExit”? Why?

前端 未结 22 1868
佛祖请我去吃肉
佛祖请我去吃肉 2020-11-22 02:59

I have the following code:

info = new System.Diagnostics.ProcessStartInfo(\"TheProgram.exe\", String.Join(\" \", args));
info.CreateNoWindow = true;
info.Win         


        
22条回答
  •  温柔的废话
    2020-11-22 03:02

    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:

    • 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).

    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:

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

提交回复
热议问题