首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >子任务取消,父任务完成?

子任务取消,父任务完成?
EN

Stack Overflow用户
提问于 2015-02-17 14:47:30
回答 3查看 1.9K关注 0票数 6

当孩子被附加时,我试图理解.net任务的行为。

我有以下测试代码:

代码语言:javascript
复制
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);
}

其结果是:

代码语言:javascript
复制
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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-02-17 15:18:44

这是MSDN上所述的预期行为。父任务必须对子任务进行 (向下滚动到取消部分)。父任务必须处理所有良性错误(如取消)。

要使父任务失败,只需等待并传递令牌:

代码语言:javascript
复制
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()。这个文章非常有趣。

票数 4
EN

Stack Overflow用户

发布于 2015-02-17 15:30:55

你的例子很复杂,隐藏了你的直觉行为,你的期望是错误的。

让我们从工作示例开始:

代码语言:javascript
复制
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()是不够的。

您需要概念化parentchild执行流是如何结合在一起的,以便了解为什么您的期望是错误的。

代码语言:javascript
复制
Main thread: ---\------------------------------------[Cancel]-----/
Parent:          \---\-----[Check cancellation]------------------/
Child:                \------------------------------[Cancel]---/

从上面的图表中可以看到,在请求取消之前,父节点会检查取消方式。子接收取消信号,因为它基本上等待取消被触发。现在,如果您将相同的机制放在父程序中,它将接收取消信号,因为在取消信号发出之前,它不会完成它的工作。

票数 1
EN

Stack Overflow用户

发布于 2018-08-19 20:51:53

当附加子任务取消时

文档的标准版本声明您需要等待父任务。

当我试图在主线程中等待parentTask.Wait()时-没有错误。

老旧‘等待父任务’。

当我试图在parentTask中等待parentTask(),然后在主线程中等待parentTask.Wait()时,我得到了一个错误。

所以目前的文件误导了我们。另一方面,在默认情况下,父任务应该等待所有附加子任务。因此,我不明白为什么要显式地等待childTask.Wait()在parentTask中捕获主线程中的TaskCanceledException。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28564074

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档