Harrison
Harrison

Reputation: 3963

Task.ContinueWith Chain Sequence of Events

How do I get a ContinueWith to wait for two tasks to complete instead of just one?

I wanted to determine how I can chain a set of Tasks together and have one run after the other having several levels of chaining. I have three levels of chaining. In the fist level I have a single task. I wanted the top level to finish before the second level starts. In the second level I have 3 tasks. I want 2 of the three tasks to complete before the third level starts.


TopLevel > SecondLevel A \ ThirdLevel 
           SecondLevel B /
           SecondLevel C - Don't wait for this one for the third level

I have written the following sample program to test out how this would work as follows

class Program
{
    private static Random rand = new Random();
    public static Random Rand { get { return rand; } }
    static void Main(string[] args)
    {

        Task topLevelTask = new Task(() => DoSomeWork("topLevelTask"));
        Task secondLevelTaskA = topLevelTask.ContinueWith((task) => DoSomeWork("secondLevelTaskA"), TaskContinuationOptions.AttachedToParent);
        Task secondLevelTaskB = topLevelTask.ContinueWith((task) => DoSomeWork("secondLevelTaskB"), TaskContinuationOptions.AttachedToParent);
        Task secondLevelTaskC = topLevelTask.ContinueWith((task) => DoSomeWork("secondLevelTaskC"), TaskContinuationOptions.AttachedToParent);
        Task thirdLevelTask = secondLevelTaskA.ContinueWith((task) => DoSomeWork("thirdLevelTask"), TaskContinuationOptions.AttachedToParent);

        topLevelTask.Start();
        Console.ReadLine();
    }

    private static void DoSomeWork(string task)
    {
        int sleep = Rand.Next(10000);
        Console.WriteLine("Thread {0}: Ticks {1}: Task {2}: Sleep: {3}", Thread.CurrentThread.ManagedThreadId, DateTime.Now, task, sleep);
        Thread.Sleep(sleep);
        Console.WriteLine("Complete Task {0}", task);
    }
}

For the most part this does exactly what I want. It starts the first task and waits for it to finish, starts the 3 second level tasks in parallel. However, I can't figure out how to set up the third level to wait for both taskA and taskB since the ContinueWith is set with a single parent task.

I have attempted to put ContinueWith for the third level task on both taskA and taskB but then it runs twice. Any help would be appreciated. Here is the output of my sample program.

Program Output

Upvotes: 0

Views: 2588

Answers (2)

svick
svick

Reputation: 244958

You're looking for ContinueWhenAll():

Task thirdLevelTask = Task.Factory.ContinueWhenAll(
    new[] { secondLevelTaskA, secondLevelTaskB },
    tasks => DoSomeWork("thirdLevelTask"),
    TaskContinuationOptions.AttachedToParent);

The advantage of this over Task.WhenAll().ContinueWith() is that it will work on .Net 4.0 too. And if you're on .Net 4.5, it would be probably better to use async-await instead of ContinueWith().

Upvotes: 4

Harrison
Harrison

Reputation: 3963

I figured it out. If I replace

Task thirdLevelTask = secondLevelTaskA.ContinueWith((task) => DoSomeWork("thirdLevelTask"), TaskContinuationOptions.AttachedToParent);

with

Task thirdLevelTask = Task.WhenAll(secondLevelTaskA,secondLevelTaskB).ContinueWith((task) => DoSomeWork("thirdLevelTask"), TaskContinuationOptions.AttachedToParent);

It will do what I want. Here is the new output.

enter image description here

Upvotes: 0

Related Questions