When I use CancelAfter(), the Task is still running

后端 未结 3 1295
[愿得一人]
[愿得一人] 2021-01-13 20:31

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

3条回答
  •  无人及你
    2021-01-13 21:18

    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();
    

提交回复
热议问题