Dimitri
Dimitri

Reputation: 2878

Parent task does not wait for child task to complete

So here is my code

Task<int[]> parent = Task.Run(() =>
{
    var result = new int[3];

    TaskFactory tf = new TaskFactory(TaskCreationOptions.AttachedToParent, TaskContinuationOptions.ExecuteSynchronously);

    for (int i = 0; i < result.Length; i++)
    {
        int j = i;
        tf.StartNew(() => result[j] = GetRandomNumber(j));
    }

    return result;
});

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

finalTask.Wait();

Basically I create 3 Tasks which are children of Task called parent (I guess). I excpect parent task to wait for all three child tasks to complete. After that the finalTask would be waited to execute because of finalTask.Wait(); this statemant. But things do not happen as expected. I mean the application exits before the any of GetRandomNumber calls finishes. Some part of the code in here is copied from book which stated that those parent task should wait for child task to complete which apparently is not happening. Am I missing something here ?

this is what GetRandomNumber does

public static int GetRandomNumber(int ii)
{
    Random rand = new Random();

    for (int i = 0; i < 1000000000; i++) { } // imitate some jobs

    return rand.Next(1000);
}

This code does the same thing

Task<int[]> parent = Task.Run(() =>
{
    var result = new int[3];

    for (int i = 0; i < result.Length; i++)
    {
        int j = i;
        new Task(() => result[j] = GetRandomNumber(j), TaskCreationOptions.AttachedToParent).Start();
    }

    return result;
});

Upvotes: 7

Views: 4583

Answers (3)

Lokesh
Lokesh

Reputation: 129

Please use the code as below:

static void RunParentTask()
    {
        Task<int[]> parent = Task.Factory.StartNew<int[]>(() =>
        {
            var results = new int[3];

            TaskFactory<int> factory = new TaskFactory<int>(TaskCreationOptions.AttachedToParent,
                                                            TaskContinuationOptions.ExecuteSynchronously);
            factory.StartNew(() => results[0] = 1);
            factory.StartNew(() => results[1] = 2);
            factory.StartNew(() => results[2] = 3);

            return results;
        });

        parent.Wait();

        foreach (var item in parent.Result)
        {
            Console.WriteLine(item);
        }
    }

Upvotes: 2

Douglas
Douglas

Reputation: 54917

This behaviour is due to your use of the Task.Run method, which forbids child tasks from being attached to the parent:

The Run method is a simpler alternative to the StartNew method. It creates a task [whose] CreationOptions property value is TaskCreationOptions.DenyChildAttach.

To resolve, simply change your first line from

Task<int[]> parent = Task.Run(() =>

to

Task<int[]> parent = Task.Factory.StartNew(() =>

Upvotes: 14

Matt Smith
Matt Smith

Reputation: 17474

In Task.Run's documentation, you'll find that it specifies

Its CreationOptions property value is TaskCreationOptions.DenyChildAttach.

So, even though you specify TaskCreationOptions.AttachedToParent, it is ignored.

Upvotes: 8

Related Questions