当孩子被附加时,我试图理解.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,尽管两个任务共享令牌,并且附加了子任务。
当取消发生时,如何使父任务返回状态Canceled?
注意到,如果我抛出异常,两个任务都返回Faulted。
发布于 2015-02-17 15:18:44
这是MSDN上所述的预期行为。父任务必须对子任务进行等 (向下滚动到取消部分)。父任务必须处理所有良性错误(如取消)。
要使父任务失败,只需等待并传递令牌:
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);如果您使用这段代码来做一些有意义的事情,而不仅仅是为了测试,您还应该考虑使用简化的Task.Run(),它支持async委托而不是Task.Factory.StartNew()。这个文章非常有趣。
发布于 2015-02-17 15:30:55
你的例子很复杂,隐藏了你的直觉行为,你的期望是错误的。
让我们从工作示例开始:
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);
}为了取消父进程,需要调用父token.ThrowIfCancellationRequested()正文中的某个位置。但是,仅仅调用token.ThrowIfCancellationRequested()是不够的。
您需要概念化parent和child执行流是如何结合在一起的,以便了解为什么您的期望是错误的。
Main thread: ---\------------------------------------[Cancel]-----/
Parent: \---\-----[Check cancellation]------------------/
Child: \------------------------------[Cancel]---/从上面的图表中可以看到,在请求取消之前,父节点会检查取消方式。子接收取消信号,因为它基本上等待取消被触发。现在,如果您将相同的机制放在父程序中,它将接收取消信号,因为在取消信号发出之前,它不会完成它的工作。
https://stackoverflow.com/questions/28564074
复制相似问题