Avoid Deadlocks when Reading StandardOutput from a Process in C#

Let’s start with some C# code that kicks off a new Process like this:

System.Diagnostics.Process p = System.Diagnostics.Process.Start(info);
p.WaitForExit();
Console.WriteLine(p.StandardOutput.ReadToEnd());

The process will do some Console.Write, and we wan’t to capture that. In order to capture the child Process’ output, we’ll read StandardOutput. That will often work great… until it doesn’t.

This can cause deadlocks where your parent process is stuck waiting due to a variety of scenarios.

  1. The child process never exits
  2. The child process writes so much data that it needs to be consumed with a stream pattern.

A good pattern is to set up event handlers on OutputDataReceived. After you append your event handler, then you need to call BeginOutputReadLine

using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
{
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();

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))
{
// Your process finished and check process.ExitCode now.
}
else
{
// Your process timed out.
}
}
}

This pattern is also very good at setting up a non-infinite wait time for your child process. Many other solution patterns for managing child processes assume an infinite wait, and that is often not a good choice for many of these advanced needs.