Task.ContinueWith和TaskContinuationOptions.AttachedToParent

时间:2013-04-08 14:46:34

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

我尝试将Task.ContinueWithTaskContinuationOptions.AttachedToParent一起使用来执行延续任务,例如

Task outerTask = new Task(() => Console.WriteLine("Outer"));
Task innerTask = outerTask.ContinueWith(t =>
    {
        Thread.Sleep(500);
        Console.WriteLine("Inner");
    }, 
    TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.OnlyOnRanToCompletion);
outerTask.Start();
outerTask.Wait();
Console.WriteLine("Outer done");

此代码的输出为

Outer
Outer done
Inner

但我期望/试图实现的是

Outer
Inner
Outer done

是否可以使用AttachedToParent阻止外部任务完成,或AttachedToParent仅对嵌套任务有效?

编辑:

我想要实现的目标是,当outerTask成功完成时,我希望运行一个延续任务。我希望outerTask将异常从innerTask传播到调用者,而不必处理innerTask。如果outerTask失败,则应立即抛出异常(outerTask.Wait()而不调用innerTask)。

3 个答案:

答案 0 :(得分:7)

您的代码中没有父子任务 您可能想要检查内部或子任务是什么,可以是两种类型:

  • detached child task or nested task,即在没有与任务创建者连接的情况下使用另一个任务的委托创建的并行任务
  • attached child task or simply child task,在这种情况下如果子任务抛出一个未处理的异常,它将被父级捕获并重新抛出

    更新

      

    “是否可以使用AttachedToParent来阻止外部任务   完成......“

         

    “我想在outerTask运行时运行一个延续任务     成功完成“

    CiCiting from last:

    • “父任务在完成所有子任务之前不会完成执行,无论是正常还是异常。父级实际上为其所有子级执行Wait命令
    • 如果子任务抛出一个未处理的异常,则由父级捕获并重新抛出。许多子任务可能会抛出异常。所有这些都将与父级直接在单个AggregateException中抛出的任何未处理异常相结合。“

对于没有父子任务的情况,请阅读 Handling Exceptions with Continuations

  

“重要的是要明白两者之间没有关系   前提和延续,除了控制之外   调度。具体而言,任务抛出的异常不是   传播到其链接的延续任务。这意味着你   应该检查您运行的所有任务中的异常。该   最简单的解决方案是等待可能出错的所有任务   使用Try / Catch块“

完成并包围Wait方法

还有链接文章提供的捕获传播异常的代码示例

更新:

  

编辑:

     

我想要实现的是我想要继续执行任务   当outerTask成功完成时。我想要outerTask   传播异常从innerTask到调用者,而不必   处理innerTask。如果outerTask失败,它应该抛出   异常(在outerTask.Wait()上没有调用innerTask)。

可能您已经看过MSDN文章Task.ContinueWith Method (Func, CancellationToken, TaskContinuationOptions, TaskScheduler)中的代码示例,该示例说明了如果前提失败/成功(反之亦然,4种组合),如何阻止/遵循继续任务。但这不是父子,而是先行 - 继续任务,因此在任一方向上都没有包含或链接异常传播。

在子父任务的情况下,在子任务已经启动之后并且仅在父母失败之后(或者显然从子女中取消父母)之后是不可能的。

答案 1 :(得分:1)

要实现您想要的效果,请更改

outerTask.Wait();

innerTask.Wait();

只要outertask完成,执行就会通过Wait并在内部任务处于Thread.Sleep时写入“Outer done”。

答案 2 :(得分:-1)

当第一个任务被视为“已完成”时,向任务添加延续的行为将永远不会改变。在运行所有(甚至一个特定的)延续之前,没有办法强制父母不被标记为“已完成”。