I have some external exe that I need to run, and read both its output and errors.
prc = new Process();
prc.StartInfo.UseShellExecute = false;
prc.StartInfo.FileName = fileName;
prc.StartInfo.Arguments = arguments;
prc.StartInfo.LoadUserProfile = true;
prc.StartInfo.RedirectStandardOutput = true;
prc.StartInfo.RedirectStandardError = true;
prc.OutputDataReceived += (sendingProcess, outLine) => outputText.AppendLine(outLine.Data);
prc.ErrorDataReceived += (sendingProcess, errorLine) => errorText.AppendLine(errorLine.Data);
prc.Start();
prc.BeginOutputReadLine();
prc.BeginErrorReadLine();
Thread where this happens may get aborted at any time and there is nothing I can change about it, so I can't use prc.WaitForExit();
as it can't be aborted until process itself is killed.
That means that every time thread gets aborted, all execution just hangs up.
So I replaced it with this in separate method:
while (!Thread.CurrentThread.ThreadState.HasFlag(ThreadState.AbortRequested) && !Thread.CurrentThread.ThreadState.HasFlag(ThreadState.Aborted))
{
if (!process.HasExited) continue;
return process.ExitCode;
}
The only problem with this is outputs. Weirdly, there are sometimes strings missing in the end both from output and error, and adding Thread.Sleep
solves this problem, meaning that asynchronous writing can't keep up for some reason.
This seems like a trivial problem, yet I can't find a reliable solition. Thread.Sleep
is hardly a good practice, and execution time is very important. What is the best way to reliably get all errors and output?
The problem with the output is that the write ends of the anonymous pipes used to carry it to your process may not be flushed until the process exits - it doesn't always happen, but you can't rely on it not happening. Instead, why not run the process stuff, including WaitForExit()
(or maybe just WaitForExit()
) in a separate thread? Your original thread can wait for this worker to finish in Thread.Abort
able manner (e.g. Thread.Join()
), and you'll have your complete output. Or, if you aren't worried about ThreadAbortException
but need to be able to cancel the WaitForExit()
call, you can use WaitHandle.WaitAny(prc.Handle,cancellationToken.WaitHandle)
.