AttachedToParent任务混乱

米兰j

我在理解AttachedToParent参数如何工作时遇到问题

这是示例代码:

public static void Main(string[] args)
    {
        Task<int[]> parentTask = Task.Run(()=> 
        {
            int[] results = new int[3];

            Task t1 = new Task(() => { Thread.Sleep(3000); results[0] = 0; }, TaskCreationOptions.AttachedToParent);
            Task t2 = new Task(() => { Thread.Sleep(3000); results[1] = 1; }, TaskCreationOptions.AttachedToParent);
            Task t3 = new Task(() => { Thread.Sleep(3000); results[2] = 2; }, TaskCreationOptions.AttachedToParent);

            t1.Start();
            t2.Start();
            t3.Start();

            return results;
        });

        Task finalTask = parentTask.ContinueWith(parent =>
        {
            foreach (int result in parent.Result)
            {
                Console.WriteLine(result);
            }
        });

        finalTask.Wait();
        Console.ReadLine();
    }

据我了解,当一个任务有子任务时,所有子任务都准备好后,父任务就完成了。这个例子的问题是输出看起来像这样:

0
0
0

这意味着父任务没有等待其子任务完成。获得有效结果的唯一方法0 1 2是在所有子Taks上使用Wait,方法是在return results;语句之前添加如下代码

Task[] taskList = { t1, t2, t3 };
Task.WaitAll(taskList);

我的问题是这个。TaskCreationOptions.AttachedToParent当我们还必须为每个子Task手动调用Wait方法时,为什么使用

编辑:

当我编写此问题时,我对代码进行了一些更改,现在AttachedToParent运行良好。唯一的区别是,我使用了parentTask.Start();而不是Task.Run();

public static void Main(string[] args)
    {
        Task<int[]> parentTask = new Task<int[]>(()=> 
        {
            int[] results = new int[3];

            Task t1 = new Task(() => { Thread.Sleep(3000); results[0] = 0; }, TaskCreationOptions.AttachedToParent);
            Task t2 = new Task(() => { Thread.Sleep(3000); results[1] = 1; }, TaskCreationOptions.AttachedToParent);
            Task t3 = new Task(() => { Thread.Sleep(3000); results[2] = 2; }, TaskCreationOptions.AttachedToParent);

            t1.Start();
            t2.Start();
            t3.Start();

            //Task[] taskList = { t1, t2, t3 };
            //Task.WaitAll(taskList);

            return results;
        });

        parentTask.Start();

        Task finalTask = parentTask.ContinueWith(parent =>
        {
            foreach (int result in parent.Result)
            {
                Console.WriteLine(result);
            }
        });

        finalTask.Wait();
        Console.ReadLine();
    }

我仍然不明白为什么第一个示例有问题。

testCoder

查看此博客文章:Task.Run与Task.Factory.StartNew

第一个例子:

Task.Run(someAction);

是简化的等效方法:

Task.Factory.StartNew(someAction,
         CancellationToken.None,
         TaskCreationOptions.DenyChildAttach,
         TaskScheduler.Default);

我很少做研究,使用反射器,这是方法的来源 Task.Run

public static Task Run(Func<Task> function, CancellationToken cancellationToken)
    {
      if (function == null)
        throw new ArgumentNullException("function");
      cancellationToken.ThrowIfSourceDisposed();
      if (cancellationToken.IsCancellationRequested)
        return Task.FromCancellation(cancellationToken);
      else
        return (Task) new UnwrapPromise<VoidTaskResult>(
            (Task) Task<Task>.Factory.StartNew(function,
                                  cancellationToken, 
                                  TaskCreationOptions.DenyChildAttach,
                                  TaskScheduler.Default),
            true);
    }

方法的重要参数Task.Factory.StartNewTaskCreationOptions creationOptions在方法中Task.Factory.StartNew,参数等于TaskCreationOptions.DenyChildAttach这意味着

如果尝试将子任务附加到创建的任务,则将抛出InvalidOperationException

您需要进行更改以TaskCreationOptions.None实现正确的代码行为。

方法Task.Run 不提供更改TaskCreationOptions参数的功能。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章