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时,也就不会等待那个没有被成功添加的子线程结束了。

  • 相关阅读:
    php连接mysql数据库基础
    控制操作
    巨慢IE9的加速
    推广邮件客户端(二):完美的IMAP客户端
    XPath 和 LINQ to XML 的比较
    推广邮件客户端(三):常用IMAP客户端介绍
    关于Git工具与GitHub
    Android开源项目(非组件)
    windows下使用Git获取Android源码
    Eclipse导入项目:No projects are found to import
  • 原文地址:https://www.cnblogs.com/cc299/p/13879263.html
Copyright © 2011-2022 走看看