Tuesday, August 05, 2008

Process.WaitForExit() never completes

It's been over a year since the last time I blogged.... Sorry for that, but it's been a busy year. I've decided to pick up again and try to post some tech-related random thoughts once in a while.

Today I just wanted to share a bug I found that might be interesting for some of you.

I had a small function that started a process and waited for it to finish it's work. The code looked something like this:

Process P = new Process();
P.StartInfo.UseShellExecute = false;
P.StartInfo.RedirectStandardOutput = true;
P.StartInfo.RedirectStandardError = true;
P.StartInfo.FileName = pathToProgram;

P.StartInfo.Arguments = programArguments;
P.Start();

P.WaitForExit();
P.Close();

Since the process sometimes takes a while to finish, I wanted to be able to watch what was going on, so I decided to read from stderr/stdinput to see if something went wrong. To do this, I made sure that the RedirectStandardError properties of the process was set to true (see code above), and inserted the following line to check if the application had encountered any errors:

P.WaitForExit();
string err = P.StandardError.ReadToEnd();

P.Close();

After this code had been used for a while, I noticed that once in a while the application was hanging when performing the above process. The problem only occured when a lot of data was written to standarderror.

I debugged the problem, and found out that omitting reading from StandardError removed the problem. I thought that this seemed like a strange problem, and continued to search for a solution.

After reading the documentation, I finally came up with the information that revealed the problem. The following remark in the msdn library for the RedirectStandardError property says:

"The Process component communicates with a child process using a pipe. If a child process writes enough data to the pipe to fill the buffer, the child will block until the parent reads the data from the pipe. This can cause deadlock if your application is reading all output to standard error and standard output, for example, using the following C# code."

So instead of asking the process to fill the buffer and wait for me to empty it so that the call to WaitForExit() would block, reading the contents of the buffer (P.StandardError.ReadToEnd()) before calling WaitForExit() solved the problem and made the solution a success.

Conclusion: Read the documentation. And make sure you read the remarks.