sashoalm sashoalm - 4 months ago 10
C# Question

Can a TPL task that doesn't check whether it's cancelled, still be cancelled?

I thought that the CancellationToken/CancellationTokenSource system worked a bit like a C++

volatile bool bFlagCancelled
, meaning that cancellation is voluntary on the part of the task, and relies on the task itself to check from time to time whether it is cancelled and throw an exception, either explicitly or by calling
ThrowIfCancellationRequested()
.

But if I call Cancel immediately after
StartNew()
, the task stops, and calling
Wait()
throws a
TaskCanceledException
.

For example, for this code:

CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
Task task = Task.Factory.StartNew(
() =>
{
Console.WriteLine("start sleep");
Thread.Sleep(1000);
Console.WriteLine("sleep ended");
}
, token);
// Thread.Sleep(1);
source.Cancel();
Console.WriteLine("start wait");
task.Wait();
Console.WriteLine("wait ended");


I get this output:

start wait
Exception: System.AggregateException: One or more errors occurred. ---> System.Threading.Tasks.TaskCanceledException: A task was canceled.


But if I uncomment
// Thread.Sleep(1);
, then the behavior changes and I get this output:

start sleep
start wait
sleep ended
wait ended


Now I thought maybe this is because
task.Start()
hasn't been called yet, but as far as I understand it,
StartNew()
calls
task.Start()
before returning - that's why it doesn't have the synchronization cost and is recommended vs creating a
new Task
and calling
task.Start()
yourself.

So then this means in some situations, a task will cancel spontaneously, even without checking the cancellation token. Is this the only situation where this happens, or are there more scenarios where this happens?

Answer

Task.Factory.StartNew schedules the task before returning, but it doesn't mean the task actually started to execute. So there is still room to cancel the task, if the TaskScheduler accepts it (internally, the TaskScheduler.TryDequeue method is called. The task can be marked as cancelled if it returns true).

Comments