0

Could someone explain some details of how CancellationTokenSource should be used? In my application, I am creating a number of Tasks that run concurrently. My code can’t stick around and wait for them to finish so it goes off and comes back to see if any of the tasks have finished and, for those that have finished, takes their results and processes them. There is a possibility that an event could occur that makes the results of any running task meaningless so all tasks can be cancelled and their results discarded. At first I thought I could just let each task run to completion and ignore the results but then I thought that seemed a little sloppy.

I'm assuming the correct thing to do is to create a single CancellationTokenSource and then pass its Token to each task I create.

var cts = new CancellationToken();

for (var i = 0; i < someNumber; i++)
    Task.Run(() => MyAwesomeMethod(cts.token));

Then my method would look something like this:

public void MyAwesomeMethod(CancellationToken token) {
    ...
    while (!token.IsCancellationRequested && NotDoneProcessing)
       DoSomethingAwesome()

    return someResult;
}

If I now wanted to cancel all my running tasks, I assume I could just set the token to cancelled in my main thread

cts.Cancel();

It's the next steps I'm a little unclear on. All the examples I've seen deal with a single thread and have the main code waiting for the tasks to complete, catching and handling the TaskCanceledException exception, then Disposing of the CancelationTokenSource object after the exception is caught. (yes, I know I'm not raising one)

What if I have multiple tasks running and I'm no longer interested in any of the results of these tasks after being cancelled? All I want to do is cancel any running tasks and ignore the results. Can I signal the CancellationToken and then dispose of the CancellationTokenSource right after. E.g.

cts.Cancel();
cts.Dispose();

Or do I have to wait for each of the tasks to finish before I dispose of the CancellationTokenSource?

What if I need to create new tasks right after I cancel the running tasks? Do I have to create a new CancellationTokenSource or can I reuse the existing CancellationTokenSource, assuming I haven't cancelled it?

DaveR
  • 1,295
  • 1
  • 13
  • 35
  • I was thinking that rather than the for loop on the tasks, a Task.WhenAll would work, but that doesn't look like it takes a CTS (https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.whenall?view=net-5.0) however, the TPL Parallel.For might be the ticket: https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-cancel-a-parallel-for-or-foreach-loop – Andy Stagg Jul 05 '21 at 15:57
  • @AndyStagg not at all. `Parallel.ForEach` is for data parallelism - processing large amounts of in-memory data by partitioning it and using one worker per core to process the data. – Panagiotis Kanavos Jul 05 '21 at 15:58
  • 1
    See [this answer](https://stackoverflow.com/a/30855490) in the duplicate. Most likely, you can forego disposing altogether. If you're in a situation where the wait handle was created, then you would need to delay disposing until anything that might have been waiting has been cleaned up (otherwise those might throw an `ObjectDisposedException`). As far as your second question goes, there's no way to reuse `CancellationTokenSource`. – Peter Duniho Jul 05 '21 at 15:59
  • Is MyAwesomeMethod doing data / API access? – Andy Stagg Jul 05 '21 at 16:00
  • @AndyStagg Does it matter what MyAwesomeMethod does? In the end, if it is cancelled, the results are no longer meaningful. – DaveR Jul 05 '21 at 21:12

0 Answers0