TPL继续任务:不确定谁是父任务
本文关键字:任务 继续 TPL 不确定 | 更新日期: 2023-09-27 18:22:22
ContinuationOption.AttachedToParent标志有问题。
这是我的伪代码:
Task parentTask = Task.Start(() =>
{
Task childTask = Task.Start(() => doSomething(),
ContinuationOption.AttachedToParent);
childTask.ContinueWith(() => followingMethod(),
ContinuationOption.AttachedToParent);
}
我知道如果"doSomething()"抛出异常childTask失败,parentTask也失败,因为ContinuationOption.AttachedToParent选项。
如果followingMethod()抛出异常,但parentTask状态为Completed,我会期望同样的行为。
是我做错了,还是继续任务的"父"任务不是我的"父任务"?
你的直觉是正确的,但我猜你很可能只是使用了错误的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
,因此两个嵌套任务都将分离运行(没有父任务)。我猜这就是你的问题所在。
此上下文中的父任务是您在中创建子任务的任务,就像在Task.Factory.StartNew
中的Task.Factory.StartNew
中一样。
子任务(或嵌套任务)是在另一个任务(称为父任务)的用户委托中创建的System.Threading.Tasks.task实例。子任务可以是分离的,也可以是附加的。分离的子任务是独立于其父任务执行的任务。附加的子任务是使用TaskCreationOptions.AttachedToParent选项创建的嵌套任务。
附加和分离的子任务
注册任务的延续时,该任务是先行任务,而不是父任务。当您调用ContinueWith
时,您将返回一个代表继续的任务。这是您需要检查异常的任务:
var continuation = task.ContinueWith(() => followingMethod());