Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task hierarchy example not working as expected

I am starting using Tasks in C#. I am trying to execute this code.

    private static void CreateSubtask() {

        Task<Int32[]> parent = Task.Run(() =>
        {
            var results = new Int32[3];
            new Task(() => results[0] = 0,
                TaskCreationOptions.AttachedToParent).Start();
            new Task(() => results[1] = 1,
                TaskCreationOptions.AttachedToParent).Start();
            new Task(() => results[2] = 2,
                TaskCreationOptions.AttachedToParent).Start();
            return results;
        });
        var finalTask = parent.ContinueWith(
           parentTask =>
           {
               foreach (int i in parentTask.Result)
                   Console.WriteLine(i);
           });
        finalTask.Wait();
    }

The finalTask runs only after the parent Task is finished, and the parent Task finishes when all three children are finished. You can use this to create quite complex Task hierarchies that will go through all the steps you specified.

What I got from the execution instead is three lines saying:

0
0
0

I was expecting them to be

0
1
2

Am I right?

like image 977
MaPi Avatar asked Oct 07 '13 12:10

MaPi


3 Answers

Using Task.Run with the parent task suppresses the effect of AttachedToParent on the child task:

Task.Run vs Task.Factory.StartNew by Stephen Toub.

Use Task.Factory.StartNew instead.

like image 59
usr Avatar answered Nov 14 '22 14:11

usr


The problem is that your parent task completes when it finishes starting the other three tasks, not when the other three tasks are finished.

Instead you can use Task.WhenAll to create a task that will be completed when all of the other tasks are themselves completed.

Another change to make your program more idiomatic task code is to have each inner task return their own value, rather than mutating some shared state, simply because dealing with shared state can be harder to reason about in a multithreaded environment.

var parent = Task.WhenAll(Task.Run(() => 0),
    Task.Run(() => 1),
    Task.Run(() => 2));
var finalTask = parent.ContinueWith(t =>
    {
        foreach (int n in t.Result)
            Console.WriteLine(n);
    });
finalTask.Wait();
like image 5
Servy Avatar answered Nov 14 '22 12:11

Servy


You are only starting your three sub tasks, but not waiting for them to finish. Adapt it like this, for example:

            var task1 = new Task(() => results[0] = 0,
                TaskCreationOptions.AttachedToParent);
            var task2 = new Task(() => results[1] = 1,
                TaskCreationOptions.AttachedToParent);
            var task3 = new Task(() => results[2] = 2,
                TaskCreationOptions.AttachedToParent);

            task1.Start();
            task2.Start();
            task3.Start();

            task1.Wait();
            task2.Wait();
            task3.Wait();

Also note that with your current code, it is still possible to show 0 1 2 (not 1 2 3 by the way), as it is not determined when the subtasks are running / finishing. This might also be dependent on your build configuration (debug / release).

like image 1
Dennis Avatar answered Nov 14 '22 12:11

Dennis