Locked 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 PM
    Moderator
     
      Has Code

    "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 PM
    Moderator
     
     Answered

    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.

     

     

  • Friday, October 29, 2010 9:33 PM
    Moderator
     
     

    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".