There are several objects of type Task or Task<T> . It is necessary to wait for the completion of each of these objects and to perform actions on completion. You can use the Task.Wait method, for example:

 public static void Foo() { var t1 = new Task(DoSomething1); var t2 = new Task(DoSomething2); t1.Start(); t2.Start(); t1.Wait(); t2.Wait(); Console.WriteLine("Tasks completed"); } private static void DoSomething2() { Console.WriteLine("Do something 2"); } private static void DoSomething1() { Console.WriteLine("Do something 1"); } 

However, with a large number of tasks it will look quite cumbersome. What are the ways the .NET task infrastructure offers to wait for other tasks?

    1 answer 1

    There are several ways to solve the proposed problem.

    There is a static Task.WaitAll method that takes an array of tasks as arguments and blocks the calling thread until all these tasks are completed. In addition, there are overloads of this method, which take a wait timeout (and return a sign that the tasks completed at the specified time) and / or a wait cancellation token. There is also an overload with a parameter that takes a variable number of arguments (the params ):

     public static void Foo() { var t1 = new Task(DoSomething1); var t2 = new Task(DoSomething2); t1.Start(); t2.Start(); Task.WaitAll(t1, t2); Console.WriteLine("Tasks completed"); } private static void DoSomething2() { Console.WriteLine("Do something 2"); } private static void DoSomething1() { Console.WriteLine("Do something 1"); } 

    You should not confuse the Task.WaitAll method with the Task.WaitAny method, which is waiting for any of the tasks transferred.

    If you can write using .NET 4.5, you can use the async/await keywords to wait for tasks to complete asynchronously. The Task.WhenAll method will create a task that will complete when all the tasks passed to it as arguments are completed.

    The code below will be executed synchronously until execution reaches the await instruction. At this moment, control will be transferred to the code that called the Foo method, and the waiting for the execution of tasks will occur in another thread. Upon completion of the tasks, the control will be returned to the Foo method and it will continue to work:

     public static async void Foo() { var t1 = new Task(DoSomething1); var t2 = new Task(DoSomething2); t1.Start(); t2.Start(); await Task.WhenAll(t1, t2); Console.WriteLine("Tasks completed"); } private static void DoSomething2() { Console.WriteLine("Do something 2"); } private static void DoSomething1() { Console.WriteLine("Do something 1"); } 

    In addition, the task generated by the Task.WhenAll method is a normal task, which means you can wait for it synchronously using the Task.Wait method:

     public static void Foo() { var t1 = new Task(DoSomething1); var t2 = new Task(DoSomething2); t1.Start(); t2.Start(); Task.WhenAll(t1, t2).Wait(); Console.WriteLine("Tasks completed"); } private static void DoSomething2() { Console.WriteLine("Do something 2"); } private static void DoSomething1() { Console.WriteLine("Do something 1"); } 

    Finally, the task generated by the Task.WhenAll method can be continued using the Task.ContinueWith method. This method starts the task passed to it as an argument after the completion of the specified task. In the continuation task, with this, you can handle the results and exceptions of the tasks that were originally necessary to wait:

     public static void Foo() { var t1 = new Task(DoSomething1); var t2 = new Task(DoSomething2); t1.Start(); t2.Start(); var continuation = Task.WhenAll(t1, t2).ContinueWith( t => { Console.WriteLine("Tasks completed"); }); continuation.Wait(); } private static void DoSomething2() { Console.WriteLine("Do something 2"); } private static void DoSomething1() { Console.WriteLine("Do something 1"); } 

    PS Special thanks to @NickVolynkin for offering to ask a question and answer it yourself and @PavelMayorov for the idea of ​​waiting through Task.WhenAll .