31

I have a button thats spawns 4 tasks. The same button changes to a cancel button and clicking this should cancel all 4 tasks. Should I pass the same cancel token to all 4 tasks and have them poll on the same token for IsCancelRequested ? I am confused after reading the msdn doc on createlinkedtokensource. How is this normally done ? thank you

Update: Task.WaitAll() waits tills all tasks complete execution. Similarly how to know when all tasks have been canceled once the shared cancel token source is set to cancel.

Gullu
  • 3,477
  • 7
  • 43
  • 70

3 Answers3

32

Yeah, what you said about using a single CancellationToken is correct. You can create a single CancellationTokenSource and use its CancellationToken for all of the tasks. Your tasks should check the token regularly for cancellation.

For example:

const int NUM_TASKS = 4;

CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken ct = cts.Token;

Task[] tasks = new Task[NUM_TASKS];
for (int i = 0; i < NUM_TASKS; i++)
{
    tasks[i] = Task.Factory.StartNew(() =>
    {
        while (true)
        {
            Thread.Sleep(1000);
            if (ct.IsCancellationRequested)
                break;
        }
    }, ct);
}

Task.WaitAll(tasks);

Your button can call cts.Cancel(); to cancel the tasks.

Update for question update:

There are a few ways to do what you ask. One way is to use ct.IsCancellationRequested to check cancellation without throwing, then allow your task to complete. Then Task.WaitAll(tasks) will complete when all of the tasks have been cancelled.

I've updated the code to reflect that change.

Matt
  • 4,318
  • 1
  • 27
  • 28
  • That will block the UI for at most 4 seconds – Alan Turing Sep 16 '11 at 22:05
  • 1
    This is an example that will wait for all of the tasks, and each task will check for completion every second. It's not given in the full context of a GUI app. – Matt Sep 16 '11 at 22:09
  • I agree with @Matt's answer. But I'd like to note that `var task = Task.WhenAll(tasks);` is heaps easier to manage. `WaitAll()` will throw an exception, and an ugly `AggregateException` at that - if any of the tasks faulted OR were cancelled. Please see the defined behavior of this method on [MSDN](https://msdn.microsoft.com/en-us/library/hh160384(v=vs.110).aspx). In the vast majority of cases, that behaviour means all you need to do is check the returned task (from `WhenAll()`) status – Jonno Oct 14 '15 at 06:10
  • @Matt, Thanks for your Solution. Above code i have tried with 5 or more task it is not working. Could you please tell me i can call cts.Cancel(); before Task.WaitAll. – Sudhir.net Nov 28 '18 at 09:53
3

Yes you should pass the same token and use this to cancel all the tasks in one go, if that's your intent.

TheCodeKing
  • 19,064
  • 3
  • 47
  • 70
-3

Use BackroundWorker class, set property WorkerSupportsCancellation, start tasks by calling RunWorkerAsync() and stop them using CancelAsync()

You do not neet to sync your code with the UI.

Alan Turing
  • 2,482
  • 17
  • 20
  • Developing a backgroundworker is not the solution. You use the CancellationTokenSource.Token in all your tasks and just cancel that source to get them all canceled. – MarchalPT May 06 '22 at 15:00