I want to use CancellationTokenSource stop the Task. My tests as follow:
Test 1 : Using Cancel() stopped the task sucessfully.
Test 2 : Using CancelAfter() d
Cancel()
succeeds in cancelling that task, because task had no chance to even start. When task is scheduled and it about to run - there is a check if its not already cancelled. You can verify it by modifying testFun
like this:
static Action testFun = () => {
Console.WriteLine("start");
Thread.Sleep(4000); // or other a long time operation
Console.WriteLine("Action is end");
};
And observe that when you use Cancel
- there is no "start" output to console, so task has not been started.
When you introduce a delay with CancelAfter
, or by just doing:
Task task = new Task(testFun, token);
task.Start();
Thread.Sleep(10); // < small delay
source.Cancel();
Task has a chance to start, and after it has been started - cancelling token has no effect, because nothing in the body of testFunc
checks if token has been cancelled. It's not possible for task to be magically cancelled in the middle of execution without cooperation from that task code.
Cooperation can look for example like this (though using Task.Delay
in this way is not usually recommended):
static Action testFun = (CancellationToken ct) => {
Console.WriteLine("start");
Task.Delay(4000, ct).Wait();
Console.WriteLine("Action is end");
};
Then when you start task - you pass cancellation token there:
Task task = new Task(() => testFun(token), token);
And now there is cooperation - Task.Delay
will notice that token is cancelled and will cancel Task.Delay
operation, which in turn will cancel your task (by throwing OperationCanceledException
).
Same can be done with async\await:
static async Task TestFun(CancellationToken ct) {
Console.WriteLine("start");
await Task.Delay(4000, ct);
Console.WriteLine("Action is end");
}
Task task = TestFun(token);
// no need for task.Start() here - task is already started
source.CancelAfter(100);
Console.ReadLine();