Awaiting External Processes
-
Friday, October 29, 2010 6:35 PM
It seemed to me that this asynchrony system was a glorious solution to a problem I've been having where I need to start an external process, and then wait for it to complete. Currently, I have the following code on the UI thread:
Process process = new Process();
process.Start();
process.WaitForExit();The process often takes several seconds, but I've resisted using a background worker or similar because it simply doesn't happen often enough to be worth the effort and code-scrambling.
I saw mention of extension methods in the whitepaper, but there seems to be no extension method for process.RunAsync() or something similar, leaving "await TaskEx.Run(() => process.WaitForExit());" as the only solution that looks like it'll work. Spinning up an extra thread just to call WaitForExit seems rather stupid.
I also didn't find any static methods that looked promising in any of AsyncCtpExtensions, AsyncCtpThreadingExtensions, TaskEx, or TaskExtensions.
Is there a (planned) better way to await the completion of external process?
All Replies
-
Friday, October 29, 2010 7:30 PMModerator
"Spinning up an extra thread just to call WaitForExit seems rather stupid."
If you use the standard TPL functionality, by default, it'll use a ThreadPool thread. There really shouldn't be a lot of wait time to "spin up" the thread... Since this is something that "doesn't happen often enough to be worth the effort and code-scrambling", I'd just use:
await Task.Factory.StartNew( () => { Process process = new Process(theProcessExecutable); process.Start(); process.WaitForExit(); });
Reed Copsey, Jr. - http://reedcopsey.com
If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful". -
Friday, October 29, 2010 9:28 PMModerator
The downside to using the pool in this manner is that you'll be blocking a thread for the duration of the process. If you're not spinning up many processes, this may not be a huge problem, but there's still no real need to do so. Instead, you can use a task that's not bound to a thread, e.g.
public static Task ExitedAsync(this Process p)
{
var tcs = new TaskCompletionSource<object>();
p.Exited += (s,e) => tcs.TrySetResult(null);
if (p.HasExited) tcs.TrySetResult(null);
return tcs.Task;
}With that, you can write:
await p.ExitedAsync();
and you won't be blocking any threads while asynchronously waiting for the process to exit.
- Proposed As Answer by Stephen Toub - MSFTMicrosoft Employee, Moderator Friday, October 29, 2010 9:29 PM
- Marked As Answer by Lucian Wischik, MSFTMicrosoft Employee, Owner Saturday, October 30, 2010 10:13 PM
-
Friday, October 29, 2010 9:33 PMModerator
Very true. I forgot that Process effectively implements the EAP pattern this way. This is a much better option to my suggestion.
Reed Copsey, Jr. - http://reedcopsey.com
If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

