SMGreenfield SMGreenfield - 3 months ago 25
C# Question

Elimininating Process.WaitForExit() / StandardOutput deadlock condition

I've read about this deadlock condition that I'm pretty certain is affecting my code (below). What I don't understand is: this code worked perfectly well running on Windows Server 2003 (.net 2.0) for the past 12 years. Now we've been trying to move it to Windows Server 2012, where it always deadlocks.

While my DLLs are built for "anyCPU" (still targeting .net 2.0), the executable process being run is absolutely 32-bit, and the move from Server 2003 to Server 2012 goes from a 32-bit to 64-bit OS.

I think I understand what to do to resolve the issue, but does anyone know why this behavior would have changed from Server 2003 to Server 2012?

public string DoMyProcess(string filenameAndPath, string arguments)
{
string stdout="";
int exitCode = 0;

try
{
ProcessStartInfo procStartInfo = new ProcessStartInfo();
procStartInfo.FileName = filenameAndPath;
procStartInfo.CreateNoWindow = true;
procStartInfo.Arguments = arguments;
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;

System.Diagnostics.Process theProcess = null;
try
{
theProcess = Process.Start(procStartInfo);
theProcess.WaitForExit();

exitCode = theProcess.ExitCode;

// moving this ABOVE WaitForExit should eliminate deadlocks
// But why did it always work on Server 2003 but not on Server 2012?
stdout = theProcess.StandardOutput.ReadToEnd();

}
catch (System.Exception e)
{
string errMsg = e.Message;
log_the_error("threw an exception: " + e.Message);
}
}

return stdout;
}


UPDATE:

Mystery deadlock still exists, even after changing the above code as recommended:

try
{
theProcess = Process.Start(procStartInfo);
stdout = theProcess.StandardOutput.ReadToEnd();
}
catch (System.Exception e)
{
string errMsg = e.Message;
log_the_error("threw an exception: " + e.Message);
}
}


What other conditions could cause that deadlock? If I were to examine StandardError, would it reveal anything useful?

Answer

Without a good Minimal, Complete, and Verifiable code example, it's impossible to answer completely.

What I can tell you is that your code was always broken, and always had the potential for deadlock. You fail to read anything from the process until the process exits, but the process may not be able to exit, if it writes so much data to stdout that the buffer fills and blocks the process.

If you haven't recompiled anything, but have found that you see deadlock now when you didn't before, then the most likely explanation is that the process you're starting writes more to stdout than it used to. I.e. all of the output used to fit in the buffer before, but now it doesn't. (I guess it's also possible the buffer size was reduced in the newer OS, but that seems unlikely to me.)

You should go ahead and move the call to ReadToEnd(). In fact, you should do away with the WaitForExit() altogether. If you are calling ReadToEnd(), that won't complete until the process has in fact exited anyway, so calling WaitForExit() afterwards would be pointless.