任务未按预期取消

本文关键字:取消 任务 | 更新日期: 2023-09-27 18:02:18

我们得到了以下场景:

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预期的行为是任务的操作在 task . delay (2500)被处理后大部分被取消。

但是控制台显示:

IsCancellationRequested=True
SHOULD NOT HAPPEN

这感觉就像一个bug。如果您添加CancellationToken as参数到任务。延迟-函数,它将按预期工作。

那么,如果任务中的函数使用 task,该如何处理取消。延迟,那你可能不知道?

任务未按预期取消

. net中的取消是协作的。将令牌作为参数传递给Task.Run只将令牌与返回的任务关联。

要实际取消任务,需要检查任务本身内部的令牌。如果希望在延迟内取消任务,则需要将令牌传递给Task.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);

这是一篇不错的MSDN文章:https://msdn.microsoft.com/en-us/library/dd537607(v=vs.110).aspx

调用线程没有强制结束任务;它只发出信号要求取消。如果任务已经在运行,那么它就是由用户委托来通知请求和响应适当。如果在任务运行之前请求取消,则用户委托永远不会执行,任务对象会转换进入取消状态

正如i3arnon建议的那样,您可以在执行实际工作之前检查状态并抛出异常。代码节选自文章:

...
  // Was cancellation already requested?  
      if (ct.IsCancellationRequested == true) {
         Console.WriteLine("Task {0} was cancelled before it got started.",
                           taskNum);
         ct.ThrowIfCancellationRequested();
      } 
...