Reputation: 1443
We got the following scenario:
class Program
{
static void Main(string[] args)
{
// trigger the delayed function
trigger();
// cancel the running task.
_token.Cancel();
// keep window open ;-)
Console.ReadLine();
}
private static CancellationTokenSource _token = null;
private static async void trigger()
{
_token = new CancellationTokenSource();
try
{
// run task
await Task.Run(async () =>
{
// wait time
await Task.Delay(2500);
// we should be cancelled here !!
Console.WriteLine(string.Format("IsCancellationRequested={0}", _token.Token.IsCancellationRequested));
Console.WriteLine("SHOULD NOT HAPPEN");
}, _token.Token);
}
catch (TaskCanceledException)
{
}
}
}
IMO the expected behaviour is that the operation of the task is cancelled mostly after the Task.Delay(2500) is processed.
But the console is printing:
IsCancellationRequested=True
SHOULD NOT HAPPEN
This just feels like a bug. If you add the CancellationToken as parameter to the Task.Delay-Function it will work as expected.
So how to handle a cancellation if a function inside the task uses Task.Delay, that you may not know?
Upvotes: 1
Views: 3829
Reputation: 116518
Cancellation in .Net is cooperative. Passing a token as parameter to Task.Run
only associates the token with the returned task.
To actually cancel the task you need to check the token inside the task itself. If you want the task to be canceled while inside the delay you'll need to pass the token to the Task.Delay
method. Otherwise you can only check while before or after the delay:
await Task.Run(async () =>
{
_token.Token.ThrowIfCancellationRequested();
await Task.Delay(2500, _token.Token);
_token.Token.ThrowIfCancellationRequested();
Console.WriteLine(string.Format("IsCancellationRequested={0}", _token.Token.IsCancellationRequested));
Console.WriteLine("SHOULD NOT HAPPEN");
}, _token.Token);
Upvotes: 3
Reputation: 6937
Here's a nice MSDN article: https://msdn.microsoft.com/en-us/library/dd537607(v=vs.110).aspx
The calling thread does not forcibly end the task; it only signals that cancellation is requested. If the task is already running, it is up to the user delegate to notice the request and respond appropriately. If cancellation is requested before the task runs, then the user delegate is never executed and the task object transitions into the Canceled state.
As i3arnon suggested you can check the state and throw an exception before carrying out the actual work. Code excerpt from the article:
...
// Was cancellation already requested?
if (ct.IsCancellationRequested == true) {
Console.WriteLine("Task {0} was cancelled before it got started.",
taskNum);
ct.ThrowIfCancellationRequested();
}
...
Upvotes: 1