Search code examples
.netvb.nettask-parallel-library

How can I cancel Task.WhenAll?


Currenly using the following code to wait for a collection of tasks to complete. However, I now have a situation where I want to be able to cancel/abort the WhenAll call, via a cancellation token preferably. How would I go about that?

  Dim TaskCollection As New List(Of Tasks.Task)
  For x As Integer = 1 To Threads
    Dim NewTask As Tasks.Task = TaskHandler.Delegates(DelegateKey).Invoke(Me, Proxies, TotalParams).ContinueWith(Sub() ThreadFinished())
    TaskCollection.Add(NewTask)
  Next

  Await Tasks.Task.WhenAll(TaskCollection)

I'm assuming it's going to but something along the lines of the next bit of code, but I'm not sure what would go in 'XXX'.

Await Tasks.Task.WhenAny(Tasks.Task.WhenAll(TaskCollection), XXX)

Solution

  • Use TaskCompletionSource<T> to create a task for some asynchronous condition that does not already have an asynchronous API. Use CancellationToken.Register to hook the modern CancellationToken-based cancellation system into another cancellation system. Your solution just needs to combine these two.

    I have a CancellationToken.AsTask() extension method in my AsyncEx library, but you can write your own as such:

    <System.Runtime.CompilerServices.Extension> _
    Public Shared Function AsTask(cancellationToken As CancellationToken) As Task
      Dim tcs = New TaskCompletionSource(Of Object)()
      cancellationToken.Register(Function() tcs.TrySetCanceled(), useSynchronizationContext := False)
      Return tcs.Task
    End Function
    

    Usage is as you expected:

    Await Task.WhenAny(Task.WhenAll(taskCollection), cancellationToken.AsTask())