OK, my questions is really simple. Why this code does not throw TaskCancelledException
?
static void Main()
{
var v = Task.Run(() =>
{
Thread.Sleep(1000);
return 10;
}, new CancellationTokenSource(500).Token).Result;
Console.WriteLine(v); // this outputs 10 - instead of throwing error.
Console.Read();
}
But this one works
static void Main()
{
var v = Task.Run(() =>
{
Thread.Sleep(1000);
return 10;
}, new CancellationToken(true).Token).Result;
Console.WriteLine(v); // this one throws
Console.Read();
}
Cancellation in Managed Threads:
You didn't write any code inside your
Task.Run
method to access yourCancellationToken
and to implement cancellation - so you effectively ignored the request for cancellation and ran to completion.I think because you're not invoking the method
ThrowIfCancellationRequested()
from your CancellationToken object. You're ignoring, in this way, the request for the cancellation of the task.You should do something like this:
The second variant of your code works, because you're already initializing a token with a
Canceled
state set to true. Indeed, as stated here:the cancellation has already been requested and then the exception
TaskCanceledException
will be immediately thrown, without actually starting the task.There is a difference in canceling a running task, and a task scheduled to run.
After the call to the Task.Run method, the task is only scheduled, and probably have not been executed yet.
When you use the Task.Run(..., CancellationToken) family of overloads with cancellation support, the cancellation token is checked when the task is about to run. If the cancellation token has IsCancellationRequested set to true at this time, an exception of the type TaskCanceledException is thrown.
If the task is already running, it is the task's responsibility to call the ThrowIfCancellationRequested method, or just throw the OperationCanceledException.
According to MSDN, it's just a convenience method for the following:
Not the different kind of exception used in this two cases:
Also note that
TaskCanceledException
derives fromOperationCanceledException
, so you can just have onecatch
clause for theOperationCanceledException
type:Another implementation using Task.Delay with token instead it Thread.Sleep.