Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When and why to pass CancellationToken to TaskCompletionSource.SetCanceled?

I don't understand what the CancellationToken parameter is for?

Passing the CancellationToken or not does not make any difference.

public async void test()
{
    var cts = new CancellationTokenSource();
    var tcs = new TaskCompletionSource();
    tcs.SetCanceled(cts.Token);

    try
    {
        await tcs.Task;
    }
    catch (TaskCanceledException e)
    {
        Console.WriteLine($"{e.Message}");
    }
}
like image 472
K 1 Avatar asked Oct 12 '25 16:10

K 1


2 Answers

As ProgrammingLlama suggested, that argument sets the CancellationToken property on the exception that is raised when the task's result is observed. So the exception caught by test will have that property set to the cancellation token passed in.

I believe that the CancellationToken property was an attempt at being able to distinguish between different sources of cancellation; however, due to linked cancellation tokens, this property is not useful in the general case.

Side notes:

  • Avoid async void.
  • Always dispose or cancel your CancellationTokenSources.
  • Use await instead of ContinueWith.
like image 145
Stephen Cleary Avatar answered Oct 14 '25 06:10

Stephen Cleary


The TPL is inconsistent regarding the state of the CancellationToken that is cancelling a Task. The Task.FromCanceled API requires the token to be canceled, otherwise it throws an ArgumentOutOfRangeException. On the contrary the TaskCompletionSource.SetCanceled API tolerates non-canceled tokens, allowing the paradoxical situation of a canceled task associated with a non-canceled token.

An additional complication is that sometimes a canceled task throws an OperationCanceledException, and other times the derived class TaskCanceledException. I am pretty sure that if Microsoft could design the TPL again from scratch, they would clean up the API and avoid these inconsistencies.

I am adding as a bonus the information that it is possible to observe the CancellationToken associated with a Task, without incurring the cost of exception handling:

CancellationToken token = new TaskCanceledException(tcs.Task).CancellationToken;

Actually the Task class has a CancellationToken property, but it is inaccessible because it is internal.

like image 44
Theodor Zoulias Avatar answered Oct 14 '25 06:10

Theodor Zoulias