Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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)
like image 551
iguanaman Avatar asked Dec 01 '14 22:12

iguanaman


People also ask

How do I cancel async tasks?

You can cancel an asynchronous operation after a period of time by using the CancellationTokenSource. CancelAfter method if you don't want to wait for the operation to finish.

Does task WhenAll block?

WhenAll the task complete is executed before the other tasks are completed. This means that Task. WhenAll doesn't block the execution.

How do I cancel a CancellationToken?

CancellationToken is immutable and must be canceled by calling CancellationTokenSource. cancel() on the CancellationTokenSource that creates it. It can only be canceled once. If canceled, it should not be passed to future operations.


3 Answers

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())
like image 56
Stephen Cleary Avatar answered Oct 19 '22 13:10

Stephen Cleary


Dim tcs as new TaskCompletionSource(Of Object)()
Await Tasks.Task.WhenAny(Tasks.Task.WhenAll(TaskCollection), tcs)

To cancel, call tcs.SetResult(Nothing). This will fire your Task.WhenAny.

like image 20
Jonathan Allen Avatar answered Oct 19 '22 12:10

Jonathan Allen


More elegant from my opinion :

await Task.Run(()=> Task.WaitAll(myArrayOfTasks), theCancellationToken);
like image 1
Artaban Avatar answered Oct 19 '22 12:10

Artaban