NotOnRanToCompletion Continuation没有';取消父任务时不运行

本文关键字:任务 运行 取消 Continuation 没有 NotOnRanToCompletion | 更新日期: 2023-09-27 18:21:11

我正在尝试测试一个场景,在这个场景中,我有一个可以取消的任务,如果先行任务没有完成,则应该运行一个延续。代码示例如下:

static void Main(string[] args)
{
    var source = new CancellationTokenSource();
    var task = Task.Factory.StartNew(() =>
        {
            while (true)
            {
                source.Token.ThrowIfCancellationRequested();
            }
        }, source.Token);
    var continuation = task.ContinueWith(t =>
        {
            Console.WriteLine("Continuation");
            if (t.Status == TaskStatus.Faulted)
            {
                Console.WriteLine("Antecedent Faulted: " + t.Exception.Message);
            }
        }, source.Token, TaskContinuationOptions.NotOnRanToCompletion | TaskContinuationOptions.AttachedToParent, TaskScheduler.Current);
    var cancellation = Task.Factory.StartNew(() =>
        {
            Thread.Sleep(1000);
            source.Cancel();
        });
    try
    {
        continuation.Wait();
    }
    catch (AggregateException)
    {
        Console.WriteLine("AggregateException");
    }
    Console.WriteLine("Done");
    while (!Console.KeyAvailable) { }
}

该程序的输出为:

AggregateException
Done

在某种程度上,我明白了。主任务被取消了,这最终引发了一个TaskCanceledException,它被封装在AggregateException中。问题是,这是意料之中的行为吗?如果是这样,那么TaskStatus有什么用。如果没有执行延续,那么它在延续中出错了?我甚至为ConsoleKeyAvailable设置了一个循环检查,以防继续运行以及抛出AggregateException。

NotOnRanToCompletion Continuation没有';取消父任务时不运行

我相信发生这种情况的原因是您将source.Token作为CancellationToken传递给task.ContinueWith调用。尽管传递了NotOnRanToCompletion作为继续选项,但令牌在继续任务开始之前被取消的事实意味着调度器可以立即将其转换到取消状态,而无需实际运行它。