none
How does TaskCreationOptions.AttachedToParent work on task hierarchy?

    Question

  • According to the document (http://msdn.microsoft.com/en-us/library/dd997417(v=VS.100).aspx), if AttachedToParent is presented, then outer task waits for inner tasks to complete. However, it seems more complex than that:

            static void DoNotWaitingOnNestedTasks()
            {
                var rootTask = Task.Factory.StartNew(() =>
                {
                    var nested1 = Task.Factory.StartNew(() =>
                    {
                        var child1 = Task.Factory.StartNew(() =>
                        {
                            Thread.Sleep(200);
                            Console.WriteLine("Child task 1 done.");
                        }, TaskCreationOptions.AttachedToParent);

                        Thread.Sleep(100);
                        Console.WriteLine("Nested task 1 done.");
                    });

                    var child2 = Task.Factory.StartNew(() =>
                    {
                        var child3 = Task.Factory.StartNew(() =>
                        {
                            Thread.Sleep(50);
                            Console.WriteLine("Child task 3 done.");
                        }, TaskCreationOptions.AttachedToParent);

                        Thread.Sleep(10);
                        Console.WriteLine("Child task 2 done.");
                    }, TaskCreationOptions.AttachedToParent);

                    Console.WriteLine("Root task done.");
                });

                rootTask.Wait();
                Console.WriteLine("Waiting done.");

                // Keep the console window open in debug mode.
                Console.WriteLine("Press any key to exit");
                Console.ReadKey();
            }

    The output of this example is:

    Root task done.
    Child task 2 done.
    Child task 3 done.
    Waiting done.
    Press any key to exit
    Nested task 1 done.
    Child task 1 done.
    Press any key to continue . . .

    My question is: Shouldn't the output be like the following, if the parent were to wait for the child (one with .AttachedToParent attached):

    Root task done.
    Child task 3 done.    <=
    Child task 2 done.    <=
    Waiting done.
    Press any key to exit
    Child task 1 done.    <=
    Nested task 1 done. <=
    Press any key to continue . . .

    How does AttachedToParent actually work behind the scene? (Does it call Wait?) Apparently it does not make asychronous to become sequential. Any input? Thanks.

    Vincent

    Wednesday, April 21, 2010 3:22 PM

Answers

  • Hi Vincent,

    I think your expected output assumes that the following two statements are functionally equivalent:

    1 - Task.Factory.StartNew(() => { }, TaskCreationOptions.AttachedToParent);
    2 - Task.Factory.StartNew(() => { }).Wait();

    They are not.  As you deduced, AttachedToParent does not turn StartNew (or any other Task scheduling APIs) into a synchronous call.

    I think the best way to describe this is that a parent Task "will not complete (i.e. transition to the RanToCompletion, Canceled, or Faulted state)" until all of its child Tasks complete.  In the current implementation, the Wait() method is not called to achieve this behavior.  Essentially, the parent Task keeps a count of its children, each child decrements that count when it completes, and the parent Task does not complete until its child count reaches zero.

    Hope this clears a few things up,
    Danny

    Wednesday, April 21, 2010 6:17 PM

All replies

  • Hi Vincent,

    I think your expected output assumes that the following two statements are functionally equivalent:

    1 - Task.Factory.StartNew(() => { }, TaskCreationOptions.AttachedToParent);
    2 - Task.Factory.StartNew(() => { }).Wait();

    They are not.  As you deduced, AttachedToParent does not turn StartNew (or any other Task scheduling APIs) into a synchronous call.

    I think the best way to describe this is that a parent Task "will not complete (i.e. transition to the RanToCompletion, Canceled, or Faulted state)" until all of its child Tasks complete.  In the current implementation, the Wait() method is not called to achieve this behavior.  Essentially, the parent Task keeps a count of its children, each child decrements that count when it completes, and the parent Task does not complete until its child count reaches zero.

    Hope this clears a few things up,
    Danny

    Wednesday, April 21, 2010 6:17 PM
  • Danny,

    That does make sense to use the status of an asynchrous call, not the finishing line of its content (take child2 for example), as the base line for masuring its final state. It's after all, an asynchrous call. 

    Thanks for the quick respones and explaination.

    Vincent

     

    Wednesday, April 21, 2010 7:46 PM