3

I am using the solution provided in: https://stackoverflow.com/a/19104345/2713516 to run WaitForExit async, however, I want to use the Int32 parameter overload (https://msdn.microsoft.com/en-us/library/ty0d8k56(v=vs.110).aspx), as in process.WaitForExit(10000).

How do I alter this extension method so it works with the timeout parameter?

Side question: I also saw someone mentioned (https://stackoverflow.com/a/32994778/2713516) that I should dispose the cancellationToken at some point, shouldn't I use a dispose/using within the method then? and How?

/// <summary>
/// Waits asynchronously for the process to exit.
/// </summary>
/// <param name="process">The process to wait for cancellation.</param>
/// <param name="cancellationToken">A cancellation token. If invoked, the task will return 
/// immediately as canceled.</param>
/// <returns>A Task representing waiting for the process to end.</returns>
public static Task WaitForExitAsync(this Process process, 
    CancellationToken cancellationToken = default(CancellationToken))
{
    var tcs = new TaskCompletionSource<object>();
    process.EnableRaisingEvents = true;
    process.Exited += (sender, args) => tcs.TrySetResult(null);
    if(cancellationToken != default(CancellationToken))
        cancellationToken.Register(tcs.SetCanceled);

    return tcs.Task;
}
Community
  • 1
  • 1
user2713516
  • 2,983
  • 5
  • 23
  • 49
  • You could use the 'no built-in timeout' pattern from http://stackoverflow.com/questions/25683980/timeout-pattern-on-task-based-asynchronous-method-in-c-sharp – John Apr 11 '16 at 10:38
  • You're already passing a `CancellationToken` - that's already more useful than a time out. Just cancel after the timeout has elapsed, e.g. `new CancellationTokenSource(timeout).Token`. – Luaan Apr 11 '16 at 12:57
  • thanks for the suggestions – user2713516 Apr 11 '16 at 16:53

1 Answers1

3

You'll need to alter the method signature and the apply the result from the process itself. For example consider the following:

/// <summary>
/// Waits asynchronously for the process to exit.
/// </summary>
/// <param name="process">The process to wait for cancellation.</param>
/// <param name="cancellationToken">A cancellation token. If invoked, the task will return 
/// immediately as canceled.</param>
/// <returns>A Task representing waiting for the process to end.</returns>
public static Task WaitForExitAsync(this Process process, 
    int milliseconds,
    CancellationToken cancellationToken = default(CancellationToken))
{
    if (process.HasExited)
    {
        return Task.CompletedTask;
    }

    var tcs = new TaskCompletionSource<object>();
    process.EnableRaisingEvents = true;
    process.Exited += (sender, args) => tcs.TrySetResult(null);
    if (cancellationToken != default(CancellationToken))
    {
        cancellationToken.Register(tcs.SetCanceled);
    }

    return process.HasExited
        ? Task.CompletedTask
        : Task.WhenAny(tcs.Task, Task.Delay(milliseconds));
}

Now, if the process has not ended the task will still be returned after the delay. An alternative would be to do a Task.Run with the invocation to the desired overload like this:

/// <summary>
/// Waits asynchronously for the process to exit.
/// </summary>
/// <param name="process">The process to wait for cancellation.</param>
/// <param name="cancellationToken">A cancellation token. If invoked, the task will return 
/// immediately as canceled.</param>
/// <returns>A Task representing waiting for the process to end.</returns>
public static Task WaitForExitAsync(this Process process, 
    int milliseconds,
    CancellationToken cancellationToken = default(CancellationToken)) =>
    process.HasExited
        ? Task.CompletedTask
        : Task.Run(() => process.WaitForExit(milliseconds), cancellationToken);
}
David Pine
  • 23,787
  • 10
  • 79
  • 107