Reputation: 5452
I'm perplex on the cancellation of several tasks and continue with a task to display result. According to what I understood, this program should display
Tasks canceled
CancellationTokenSource cts = new CancellationTokenSource();
List<Task> tasks = new List<Task>();
for(int i= 0; i<3; i++)
{
tasks.Add(Task.Run(() =>{
while(!cts.Token.IsCancellationRequested)
Thread.Sleep(500);
// Uncomment this to see 'Tasks canceled' in the result
//if(cts.Token.IsCancellationRequested)
// cts.Token.ThrowIfCancellationRequested();
},cts.Token));
}
Task.WhenAll(tasks).ContinueWith(task =>
{
if(task.IsCanceled)
Console.WriteLine("Tasks canceled");
if(task.IsCompleted)
Console.WriteLine("Tasks completed");
});
Thread.Sleep(2000);
cts.Cancel();
Unfortunately it display
Tasks completed
If i uncomment the throwing of cancel exception the program display
Tasks canceled
Tasks completed
Why? it seems that I missed something but I do not see what...
Upvotes: 0
Views: 2082
Reputation: 7017
In first case this is what your code says it to do - stop looping when cancellation is requesting. After it exits loop, there is nothing more to execute hence task is complete.
By design to really cancel task, you need to throw exception to change execution flow. In fact, if
statement is not needed in your code sample - that ThrowIfCancellationRequested
method will handle this check by itself and will throw exception if cancellation has been requested.
Regarding last part, here is excerpt from MSDN:
IsCompleted will return true when the task is in one of the three final states: RanToCompletion, Faulted, or Canceled.
https://msdn.microsoft.com/en-us/library/system.threading.tasks.task.iscompleted(v=vs.110).aspx
So the task is complete even if it is was cancelled.
Upvotes: 1
Reputation: 11963
based on the doc
Task.WhenAll
Creates a task that will complete when all of the Task objects in an array have completed.
so the task is guarantee to be in a complete state after all of your 3 tasks ended
What you want is probably
Task.WhenAll(tasks).Wait();
Foreach(Task task in tasks)
{
if(task.IsCanceled)
Console.WriteLine("Tasks canceled");
if(task.IsCompleted)
Console.WriteLine("Tasks completed");
}
Edit: The reason why the task is not canceled is because you never throw that exception. Lets imagine this case: Your task is almost done when you call cts.Cancel();
Right after you call it the task completed. So nothing in your task is canceled and thus its not marked as canceled.
Upvotes: 0