【问题标题】:Why there is no exception when I cancel the token in Task.Delay?为什么我在Task.Delay中取消token时没有异常?
【发布时间】:2022-01-31 16:25:52
【问题描述】:

我是任务并行库的新手,下面是我的简单应用程序:

static void Main(string[] args)
{
    CancellationTokenSource cts = new CancellationTokenSource();

    var task = Task.Delay(2000, cts.Token);
    cts.Cancel();

    var exceptionProp = task.Exception;  // <------why the task's Exception is null

    Console.ReadLine();
}

据我对Task.Delay(int millisecondsDelay, CancellationToken cancellationToken)的理解是,当cancellationToken被取消时,会抛出一个TaskCanceledException

但我不明白为什么exceptionProp(任务的AggregateException 属性)在我的应用程序中为空,因为我明确取消了令牌,TaskCanceledException 应该在task.Exception 中?

【问题讨论】:

  • 任务不会设置Exception,除非它被等待或在执行过程中发生实际异常。您应该检查Status 属性以了解它是否被取消
  • docs.microsoft.com/en-us/dotnet/standard/parallel-programming/…: "注意这个异常表示取消成功,而不是故障情况。因此,任务的Exception属性返回null"。

标签: c# .net task-parallel-library


【解决方案1】:

来自Task.Exception 属性的文档:

获取导致Task 提前结束的AggregateException。如果Task成功完成或者还没有抛出任何异常,这将返回null。

在您的情况下,任务没有成功完成,但也没有失败。它已转换到第三个完成状态,称为Canceled。当等待Canceled 任务时,它们会抛出OperationCanceledException,这是.NET 中通信取消的标准方式。但是由于它们不是Faulted,所以它们的Exception 属性是null

您可以通过查询其Status 或更简单的IsCanceled 属性来检查任务是否被取消。

附带说明,一般情况下,不能保证Task 会立即接受取消信号,并且会在调用cts.Cancel() 后同步转换到Canceled 状态。 Task.Delay 恰好创建了可即时取消的任务,但其他异步方法却没有。如果你想确保任务已经完成,你必须在取消令牌后await它。

另外请注意,目前已取消的Task.Delay 任务的延续是同步调用的,但很可能在下一个 .NET 版本 (.NET 7) 中它们将被调用asynchronously

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-24
    • 2020-04-09
    • 2019-02-09
    • 1970-01-01
    • 2020-09-02
    • 2010-11-16
    • 2012-01-22
    相关资源
    最近更新 更多