zoukankan      html  css  js  c++  java
  • C#趟坑: Wait()线程结束时,会忽略子线程

    在我们的认知里,调用parent.Wait() 时,会等待它的子线程都结束,才会向下执行。

    比如,一个线程A有B、C两个子线程,A.Wait() 是等待 A、B、C都结束,才会向下执行。

    然而,最近碰到的问题却跟我想的不一样。

    问题表象

    可以简化为,在父线程中,创建一个子线程。然后在外部等待父线程结束。如下代码:

        var parentTask =Task.Run(()=>
        {
            Print("Parent")
            var subTask = new Task(() =>
            {
                Print("Sub")
            }, TaskCreationOptions.AttachedToParent);
            subTask.Start();
        });
        parentTask.Wait();
        Print("Parent End");

    按说,parentTask.Wait()会等待父线程、子线程都结束,才会向下执行。即,期望输出  Parent   Sub   Parent End

    但结果却是,Wait并没有等待子线程结束就向下执行了。 实际输出  Parent   ParentEnd   Sub

    解决方案

    把 Task.Run 换成 new Task 或者 Task.Factory.StartNew 即可。如下:

        var parentTask =new Task(()=> //把Task.Run替换为 new Task
        {
            Print("Parent")
            var subTask = new Task(() =>
            {
                Print("Sub")
            }, TaskCreationOptions.AttachedToParent);
            subTask.Start();
        });
        parentTask.Start();
        parentTask.Wait();
        Print("Parent End");

    原因剖析

    翻一下 Task.Run 的源码。

    这个 DenyChildAttach 很可疑。

    再看看它的注释,翻译一下:任何子Task 企图绑定到当前线程上时(以AttachedToParent的形式创建),会被拒绝,子Task将独立运行

    在创建线程的源码中,也能看出这个枚举的作用:

    当创建子线程时会判断:如果 parent.CreateOption 里指定DenyChildAttach,那么,就不会执行 parent.AddNewChild() 。

    总结

    使用 Task.Run 创建的 Task,是不允许再把其他线程添加为它的子线程的。因为Task.Run内部指定了 DenyChildAttach。

    因此,在我们调用task.Wait时,也就不会等待那个没有被成功添加的子线程结束了。

  • 相关阅读:
    Vue响应式原理
    vue 与 react
    vuex
    受控组件( controlled component )与不受控制的组件( uncontrolled component )区别
    redux学习语录
    Flux
    MVC和MVVM 架构模式/设计思想
    immutable
    JS中一些兼容性问题
    @芥末的糖 ---------- node连接数据库两种方式mysql和moogoDB
  • 原文地址:https://www.cnblogs.com/cc299/p/13879263.html
Copyright © 2011-2022 走看看