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

  • 相关阅读:
    回调函数(C语言)
    main函数的参数(一)
    术语,概念
    [LeetCode] Invert Binary Tree
    关于overload和override
    第一个只出现一次的字符
    Manacher算法----最长回文子串
    C++对象模型
    回文判断
    字符串转换成整数
  • 原文地址:https://www.cnblogs.com/cc299/p/13879263.html
Copyright © 2020-2023  润新知