TPL延续任务:不确定谁是父任务

时间:2014-09-18 08:08:22

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

我遇到了ContinuationOption.AttachedToParent标志的麻烦。

这是我的伪代码:

   Task parentTask = Task.Start(() =>   
   { 
        Task childTask = Task.Start(() => doSomething(),
                                    ContinuationOption.AttachedToParent);
        childTask.ContinueWith(() => followingMethod(),  
                                    ContinuationOption.AttachedToParent);
   }

我知道如果“doSomething()”抛出并且异常childTask失败并且parentTask也失败,因为 ContinuationOption.AttachedToParent选项。

如果followMethod()抛出异常但是parentTask状态为Completed,我会期望相同的行为。

我做错了还是继续任务的“父”任务不是我的“parentTask”?

2 个答案:

答案 0 :(得分:1)

你的直觉是正确的,但我猜你最有可能只是使用了错误的API。

我知道它只是伪代码,但是Task.Start()是一个实例方法,而不是静态方法,因此不会按照您指示的方式编译,我们不知道你是如何实际开始任务的,细节也很重要。 TaskFactory.StartNew会做你想做的事,但Task.Run不会。试试这个:

Task parent = Task.Factory.StartNew(() =>
{
  Task child = Task.Factory.StartNew(
     () => { Console.WriteLine("foo"); },
     TaskCreationOptions.AttachedToParent);
  Task continuation = child.ContinueWith(
     (Task prev) => { throw new InvalidOperationException("Test"); },
     TaskContinuationOptions.AttachedToParent);
});
try
{
  parent.Wait();
}
catch (AggregateException ex)
{
  if (ex.Flatten().InnerException is InvalidOperationException)
  { 
    Console.WriteLine("The continuation exception was propagated to parent");
  }
}

如果你改变了

Task parent = Task.Factory.StartNew(...)

Task parent = Task.Run(...)

然后你不会得到你想要的行为,因为Task.Run本质上是TaskFactory.StartNew的包装器(除其他外)指定TaskCreationOptions.DenyChildAttach所以两个嵌套任务都将分离运行(没有父母)。我猜你的问题是什么。

答案 1 :(得分:0)

此上下文中的父任务是您在Task.Factory.StartNew内的Task.Factory.StartNew中创建子项任务 之内的任务。

  

子任务(或嵌套任务)是在另一个任务的用户委托中创建的System.Threading.Tasks.Task实例,称为父任务。子任务可以分离或附加。分离的子任务是独立于其父级执行的任务。附加子任务是使用TaskCreationOptions.AttachedToParent选项创建的嵌套任务。

Attached and Detached Child Tasks

当您在任务上注册续集时,该任务是先行任务,而不是父任务。 当你致电ContinueWith时,你会收到一个代表继续的任务。这是检查异常所需的任务:

var continuation = task.ContinueWith(() => followingMethod());