子任务取消,父任务完成?
Child task canceled, Parent completed?
我正在尝试了解 .net 任务在附加子项时的行为。
我有以下测试代码:
void Test()
{
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
Task child = null;
var parent = Task.Factory.StartNew(() =>
{
child = Task.Factory.StartNew(() =>
{
while (!token.IsCancellationRequested)
Thread.Sleep(100);
token.ThrowIfCancellationRequested();
}, token, TaskCreationOptions.AttachedToParent, TaskScheduler.Default);
}, token);
Thread.Sleep(500);
Debug.WriteLine("State of parent before cancel is {0}", parent.Status);
Debug.WriteLine("State of child before cancel is {0}", child.Status);
tokenSource.Cancel();
Thread.Sleep(500);
Debug.WriteLine("State of parent is {0}", parent.Status);
Debug.WriteLine("State of child is {0}", child.Status);
}
结果是:
State of parent before cancel is WaitingForChildrenToComplete
State of child before cancel is Running
A first chance exception of type 'System.OperationCanceledException' occurred in mscorlib.dll
State of parent is RanToCompletion
State of child is Canceled
显然父任务状态不是 Canceled
,即使
两个任务共享令牌,并且附加了子项。
如何在发生取消时使父任务 return 状态 Canceled
?
注意
如果我抛出异常两个任务 return Faulted
.
这是 MSDN 上所述的预期行为。父任务必须为子任务 wait(向下滚动到取消部分)。父任务必须处理所有良性故障(如取消)。
要使您的父任务失败,只需等待并传递令牌:
Task child = null;
var parent = Task.Factory.StartNew(() =>
{
child = Task.Factory.StartNew(() =>
{
while (!token.IsCancellationRequested) Thread.Sleep(100);
token.ThrowIfCancellationRequested();
}, token, TaskCreationOptions.AttachedToParent, TaskScheduler.Default);
// This is the magic line.
child.Wait(token);
}, token);
如果您使用此代码做一些有成效的事情,而不仅仅是为了测试,您还应该考虑使用支持 async
委托而不是 Task.Factory.StartNew()
的简化 Task.Run()
。这个article很有意思
你的例子很复杂,隐藏了直观的行为,你的期望是错误的。
让我们从工作示例开始:
void Test()
{
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
Task child = null;
var parent = Task.Factory.StartNew(() =>
{
child = Task.Factory.StartNew(() =>
{
while (!token.IsCancellationRequested)
Thread.Sleep(100);
token.ThrowIfCancellationRequested();
}, token, TaskCreationOptions.AttachedToParent, TaskScheduler.Default);
while (!token.IsCancellationRequested)
Thread.Sleep(100);
token.ThrowIfCancellationRequested();
}, token);
Thread.Sleep(500);
Debug.WriteLine("State of parent before cancel is {0}", parent.Status);
Debug.WriteLine("State of child before cancel is {0}", child.Status);
tokenSource.Cancel();
Thread.Sleep(500);
Debug.WriteLine("State of parent is {0}", parent.Status);
Debug.WriteLine("State of child is {0}", child.Status);
}
为了取消 parent,您需要在 parent token.ThrowIfCancellationRequested()
正文的某处调用。但是,仅调用 token.ThrowIfCancellationRequested()
是不够的。
您需要概念化 parent
和 child
执行流程是如何结合在一起的,以便了解您的期望为何错误。
Main thread: ---\------------------------------------[Cancel]-----/
Parent: \---\-----[Check cancellation]------------------/
Child: \------------------------------[Cancel]---/
从上图可以看出,parent 在请求取消之前检查取消方式。 child 收到取消信号,因为它基本上等待取消被触发。现在,如果您在 parent 中放置相同的机制,它将收到取消信号,因为在发出取消信号之前它不会完成它的工作。
当附加的子任务取消时
文档的 standard version 指出您需要等待父任务。
当我尝试在主线程中等待 parentTask.Wait() - 没有错误。
old one 'wait ON the parent task'.
当我尝试在 parentTask 中等待 childTask.Wait() 然后在主线程中等待 parentTask.Wait() - 我遇到了一个错误。
因此当前的文档具有误导性。
另一方面,默认情况下,父任务应等待所有附加的子任务。所以我不明白为什么我应该在 parentTask 中显式等待 childTask.Wait() 以在主线程中捕获 TaskCanceledException。
我正在尝试了解 .net 任务在附加子项时的行为。
我有以下测试代码:
void Test()
{
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
Task child = null;
var parent = Task.Factory.StartNew(() =>
{
child = Task.Factory.StartNew(() =>
{
while (!token.IsCancellationRequested)
Thread.Sleep(100);
token.ThrowIfCancellationRequested();
}, token, TaskCreationOptions.AttachedToParent, TaskScheduler.Default);
}, token);
Thread.Sleep(500);
Debug.WriteLine("State of parent before cancel is {0}", parent.Status);
Debug.WriteLine("State of child before cancel is {0}", child.Status);
tokenSource.Cancel();
Thread.Sleep(500);
Debug.WriteLine("State of parent is {0}", parent.Status);
Debug.WriteLine("State of child is {0}", child.Status);
}
结果是:
State of parent before cancel is WaitingForChildrenToComplete
State of child before cancel is Running
A first chance exception of type 'System.OperationCanceledException' occurred in mscorlib.dll
State of parent is RanToCompletion
State of child is Canceled
显然父任务状态不是 Canceled
,即使
两个任务共享令牌,并且附加了子项。
如何在发生取消时使父任务 return 状态 Canceled
?
注意
如果我抛出异常两个任务 return Faulted
.
这是 MSDN 上所述的预期行为。父任务必须为子任务 wait(向下滚动到取消部分)。父任务必须处理所有良性故障(如取消)。
要使您的父任务失败,只需等待并传递令牌:
Task child = null;
var parent = Task.Factory.StartNew(() =>
{
child = Task.Factory.StartNew(() =>
{
while (!token.IsCancellationRequested) Thread.Sleep(100);
token.ThrowIfCancellationRequested();
}, token, TaskCreationOptions.AttachedToParent, TaskScheduler.Default);
// This is the magic line.
child.Wait(token);
}, token);
如果您使用此代码做一些有成效的事情,而不仅仅是为了测试,您还应该考虑使用支持 async
委托而不是 Task.Factory.StartNew()
的简化 Task.Run()
。这个article很有意思
你的例子很复杂,隐藏了直观的行为,你的期望是错误的。
让我们从工作示例开始:
void Test()
{
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
Task child = null;
var parent = Task.Factory.StartNew(() =>
{
child = Task.Factory.StartNew(() =>
{
while (!token.IsCancellationRequested)
Thread.Sleep(100);
token.ThrowIfCancellationRequested();
}, token, TaskCreationOptions.AttachedToParent, TaskScheduler.Default);
while (!token.IsCancellationRequested)
Thread.Sleep(100);
token.ThrowIfCancellationRequested();
}, token);
Thread.Sleep(500);
Debug.WriteLine("State of parent before cancel is {0}", parent.Status);
Debug.WriteLine("State of child before cancel is {0}", child.Status);
tokenSource.Cancel();
Thread.Sleep(500);
Debug.WriteLine("State of parent is {0}", parent.Status);
Debug.WriteLine("State of child is {0}", child.Status);
}
为了取消 parent,您需要在 parent token.ThrowIfCancellationRequested()
正文的某处调用。但是,仅调用 token.ThrowIfCancellationRequested()
是不够的。
您需要概念化 parent
和 child
执行流程是如何结合在一起的,以便了解您的期望为何错误。
Main thread: ---\------------------------------------[Cancel]-----/
Parent: \---\-----[Check cancellation]------------------/
Child: \------------------------------[Cancel]---/
从上图可以看出,parent 在请求取消之前检查取消方式。 child 收到取消信号,因为它基本上等待取消被触发。现在,如果您在 parent 中放置相同的机制,它将收到取消信号,因为在发出取消信号之前它不会完成它的工作。
当附加的子任务取消时
文档的 standard version 指出您需要等待父任务。
当我尝试在主线程中等待 parentTask.Wait() - 没有错误。
old one 'wait ON the parent task'.
当我尝试在 parentTask 中等待 childTask.Wait() 然后在主线程中等待 parentTask.Wait() - 我遇到了一个错误。
因此当前的文档具有误导性。 另一方面,默认情况下,父任务应等待所有附加的子任务。所以我不明白为什么我应该在 parentTask 中显式等待 childTask.Wait() 以在主线程中捕获 TaskCanceledException。