AttachedToParent Task confusion

c#, console-application, multithreading, task-parallel-library

Solution

Look at this blog post: Task.Run vs Task.Factory.StartNew

The first example:

Task.Run(someAction);

is simplified equivalent of method:

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

I made little research, using reflector, here is a source of method `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);
    }

The important parameter of method `Task.Factory.StartNew` is `TaskCreationOptions creationOptions`. In method `Task.Factory.StartNew` that parameter equals `TaskCreationOptions.DenyChildAttach`. It mean that

an InvalidOperationException will be thrown if an attempt is made to attach a child task to the created task

You need to change to `TaskCreationOptions.None` to achieve right behavior of code.

Method `Task.Run` does not provide ability to change TaskCreationOptions parameter.

Problem

I have a problem understanding how `AttachedToParent` parameter works. Here is the sample code: ``` 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(); } ``` As I understand, when a Task has child Tasks, the parent Task finishes when all the child tasks are ready. The problem with this example is that the output looks like this: ``` 0 0 0 ``` This means that the parent Task was not waiting for its child tasks to finish. The only way to get a valid result `0 1 2` is to use Wait on all of the child Taks, by adding some piece of code like this before the `return results;` statement: ``` Task[] taskList = { t1, t2, t3 }; Task.WaitAll(taskList); ``` My question is this. Why do we use `TaskCreationOptions.AttachedToParent` when we also have to manually call Wait method for every child Task? Edit: While I was writing this question, I've changed code a little bit and now AttachedToParent works well. The only difference is that I've used `parentTask.Start();` instead of the `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(); } ``` I still don't understand why there is a problem with the first example.

Original source