c# - C# 考试 70-483 引用书的例子有错吗? (父/子线程)

标签 c# .net task

在第一版C# 70-483 Exam Ref , 示例 1-12 给出了将子任务附加到父任务的示例。我认为这是错误的,并希望有人在继续这个假设之前检查我的理解。示例中的代码如下:

using System;
using System.Threading.Tasks;

namespace Chapter1
{
    public static class Program
    {
        public static void Main()
        {
            Task<Int32[]> parent = Task.Run(() =>
            {
                var results = new Int32[3];

                new Task(() => results[0] = 0, TaskCreationOptions.AttachedToParent).Start();
                new Task(() => results[1] = 1, TaskCreationOptions.AttachedToParent).Start();
                new Task(() => results[2] = 2, TaskCreationOptions.AttachedToParent).Start();

                return results;
            });


            var finalTask = parent.ContinueWith(parentTask =>
            {
                foreach (var i in parentTask.Result)
                {
                    Console.WriteLine(i);
                }
            });

            finalTask.Wait();
        }

    }
}

问题出在 Task.Run 上。 MSDN explains不允许允许附加子任务。在本书出版时(2013 年),我认为这可能是 .NET 版本的问题,但 MSDN 文章是在本书出版前两年发布的。

这特别棘手,因为如果执行上面的代码,results 数组确实将其值设置为 0、1 和 2。但是,如果lambda 做任何比这更耗时的事情,数组中的那个索引没有设置值。

例如,下面的代码将“一”和“二”分别分配给results元素1和2,但元素0为空。

using System;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Chapter1
{
    public static class Program
    {
        public static void Main()
        {
            Task<String[]> parent = Task.Run(() =>
            {
                var results = new String[3];

                new Task(() => {
                    SHA256 mySHA256 = SHA256.Create();
                    byte[] messageBytes = Encoding.ASCII.GetBytes("asdf");
                    byte[] hashBytes = mySHA256.ComputeHash(messageBytes);
                    results[0] = BitConverter.ToString(hashBytes).Replace("-", "");
                }, TaskCreationOptions.AttachedToParent).Start();

                new Task(() => results[1] = "one", TaskCreationOptions.AttachedToParent).Start();
                new Task(() => results[2] = "two", TaskCreationOptions.AttachedToParent).Start();

                return results;
            });


            var finalTask = parent.ContinueWith(parentTask =>
            {
                foreach (var i in parentTask.Result)
                {
                    Console.WriteLine(i);
                }
            });

            finalTask.Wait();
        }

    }
}

当我使用任务工厂(示例中未显示)启动父任务时,一切都按预期工作,TaskCreationOptions 影响子线程的同步。

所以我的问题是:

  1. 我的理解是否正确,将 TaskCreationOptions.AttachedToParent 传递给在 Thread.Run 下创建的子任务是没有意义的?
  2. 我的假设是否正确,即本书的示例之所以有效,是因为子任务 lambda 只是执行恰好在父线程终止之前完成的分配?

最佳答案

我相信您的两个问题(断言)都是正确的。 This MSDN文章似乎涵盖得很好。

Re 2,正如文章所说,将 AttachedToParent 传递给以 Task.Run() 开始的任务会产生“不可预测”的结果,其中之一就是你观察。

我应该添加一个细微差别,即“子”任务将在 ContinueWith() 开始后继续运行,因此它们在相应的时间之前获得(一点点)额外时间来完成Console.WriteLine()

关于c# - C# 考试 70-483 引用书的例子有错吗? (父/子线程),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51812708/

相关文章:

c# - 为什么等待后 HttpContext.Current 为空?

c# - .NET Core : C# Environment. GetFolderPath 未定义

c# - 在 ASP.NET 中创建基于订阅的网站

c# - 如何以编程方式验证程序集是否使用特定证书签名?

c# - 在 RESTful WebApi 请求上运行后台线程

c# - 是否可以在自己的应用程序中使用 Windows 7 任务调度程序

c# - sql异步查询问题

c# - 用c#保存XML文件并保留空元素的格式

.net - 存储库模式和聚合根模式和 Entity Framework

java - 使用同步块(synchronized block)等待结果会导致应用程序卡住