From the most basic picture that you described, I would use the Task Paralell Library (TPL) . Comes with .NET Framework 4.0+.
You are talking about the βbestβ way to use thread pools when spawning a large number of threads. Although this is correct [the most efficient way of manging resources], TPL does all this for you - without having to worry about anything. TPL also uses several threads and waits for their completion to be also a boat ...
To do what you need, I will use TPL and Continuations . Continuing not only allows you to create a task flow, but also handle your exceptions. This is a great introduction to TPL. But to give you some idea ...
You can run the TPL task using
Task task = Task.Factory.StartNew(() => { // Do some work here... });
Now, to start the second task when the previous task is completed (by mistake or successfully), you can use the ContinueWith method
Task task1 = Task.Factory.StartNew(() => Console.WriteLine("Antecedant Task")); Task task2 = task1.ContinueWith(antTask => Console.WriteLine("Continuation..."));
So, as soon as task1 completes, task2 'fires-up' fails or is canceled and starts. Note that if task1 completed before the second line of task2 code was scheduled for immediate execution. The antTask argument passed to the second lambda is a reference to the previous task. See this link for more detailed examples ...
You can also pass on the results of continuing the antecedent task
Task.Factory.StartNew<int>(() => 1) .ContinueWith(antTask => antTask.Result * 4) .ContinueWith(antTask => antTask.Result * 4) .ContinueWith(antTask =>Console.WriteLine(antTask.Result * 4));
Note. Be sure to check out the exception handling in the first link, as this may cause a newcomer to TPL to go down.
The last thing you need to look, in particular, at what you want is children's tasks. Children are those created as AttachedToParent . In this case, the continuation will not be executed until all child tasks are completed.
TaskCreationOptions atp = TaskCreationOptions.AttachedToParent; Task.Factory.StartNew(() => { Task.Factory.StartNew(() => { SomeMethod() }, atp); Task.Factory.StartNew(() => { SomeOtherMethod() }, atp); }).ContinueWith( cont => { Console.WriteLine("Finished!") });
So, in your case, you will start your four tasks, and then wait for them to complete in the main thread.
Hope this helps.