我在理解AttachedToParent
参数如何工作时遇到了问题.
以下是示例代码:
public static void Main(string[] args) { TaskparentTask = 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(); }
据我所知,当一个Task有子任务时,父任务在所有子任务都准备就绪时结束.此示例的问题是输出如下所示:
0 0 0
这意味着父Task没有等待其子任务完成.获得有效结果的唯一方法0 1 2
是在所有子Taks上使用Wait,在return results;
语句之前添加一些这样的代码:
Task[] taskList = { t1, t2, t3 }; Task.WaitAll(taskList);
我的问题是这个.为什么TaskCreationOptions.AttachedToParent
我们还必须为每个子任务手动调用Wait方法?
编辑:
当我写这个问题的时候,我已经改变了一点代码,现在AttachedToParent工作得很好.唯一的区别是我用过parentTask.Start();
而不是用Task.Run();
.
public static void Main(string[] args) { TaskparentTask = new Task (()=> { 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(); }
我仍然不明白为什么第一个例子有问题.
看看这篇博文:Task.Run vs 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.StartNew
是TaskCreationOptions creationOptions
.在Task.Factory.StartNew
参数等于的方法中TaskCreationOptions.DenyChildAttach
.这意味着
如果尝试将子任务附加到创建的任务,则将引发InvalidOperationException
您需要更改为TaskCreationOptions.None
以实现正确的代码行为.
方法Task.Run
不提供更改TaskCreationOptions参数的功能.