When developing a parallel application, you will often have situations where a task must be completed before the main thread can continue processing. The Task Parallel Library includes several methods that allow you to wait for one or more parallel tasks
to complete. This recipe will cover two such methods: Task.Wait()
and Task.WaitAll()
.
In this recipe we will be creating three tasks, all of which read in the text classic books and produce a word count
. After we create the first task, we will wait for it to complete using Task.Wait()
, before starting the second and third task. We will then wait for both the second and third tasks to complete using Task.WaitAll()
before writing a message to the console.
Let's create a Console
application that demonstrates how to wait for task
completion.
WordCount
as the Solution name.using
statements at the top of your Program
class:using System; using System.Linq; using System.Net; using System.Threading.Tasks;
Main
method of the Program
class, add a character array containing the basic punctuation marks. We will use this array in string.Split()
to eliminate punctuation marks. Also add a string constant
for the user-agent
header of the WebClient
.char[] delimiters = { ' ', ',', '.', ';', ':', '-', '_', '/', 'u000A' }; const string headerText = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)";
WebClient
to read the Origin of Species by Darwin, and get its word count. Enter the following code in the Main
method of the Program
class just below the previous statement:var task1 = Task.Factory.StartNew(() => { Console.WriteLine("Starting first task."); var client = new WebClient(); client.Headers.Add("user-agent", headerText); var words = client.DownloadString(@"http://www.gutenberg.org/files/2009/2009.txt"); var wordArray = words.Split(delimiters, StringSplitOptions.RemoveEmptyEntries); Console.WriteLine("Origin of Species word count: {0}", wordArray.Count()); } );
Console
application:task1.Wait(); Console.WriteLine("Task 1 complete. Creating Task 2 and Task 3.");
var task2 = Task.Factory.StartNew(() => { Console.WriteLine("Starting second task."); var client = new WebClient(); client.Headers.Add("user-agent", headerText); var words = client.DownloadString(@"http://www.gutenberg.org/files/16328/16328-8.txt"); var wordArray = words.Split(delimiters, StringSplitOptions.RemoveEmptyEntries); Console.WriteLine("Beowulf word count: {0}", wordArray.Count()); }); var task3 = Task.Factory.StartNew(() => { Console.WriteLine("Starting third task."); var client = new WebClient(); client.Headers.Add("user-agent", headerText); var words = client.DownloadString(@"http://www.gutenberg.org/files/4300/4300.txt"); var wordArray = words.Split(delimiters, StringSplitOptions.RemoveEmptyEntries); Console.WriteLine("Ulysses word count: {0}", wordArray.Count()); });
Task.WaitAll()
to wait for the second and third task to complete, then prompt the user to exit the program. Task.WaitAll()
takes an array of task
as its parameter, and can be used to wait for any number of tasks to complete.Task.WaitAll(task2,task3); Console.WriteLine("All tasks complete."); Console.WriteLine("Press <Enter> to exit."); Console.ReadLine();
Although Task.Wait()
and Task.WaitAll()
are fairly self-explanatory, both have several overloads that offer different functionalities.
Task.Wait()
can take either an Int32
or TimeSpan
parameter to specify a specific period of time to wait. It can also accept a CancellationToken
token parameter for cancellation, which will be covered later in the chapter.
Task.WaitAll()
always takes an array of Task
as its first parameter, and has a second parameter which can be an Int32
or TimeSpan
as in Task.Wait
.
Another useful method not shown in the recipe is Task.WaitAny()
. WaitAny
is very similar to WaitAll
, except that it waits for only one Task
in the array of Task
to complete. The first Task
of Task
array to finish, completes the wait condition, and execution of the main thread is allowed to move forward.
It is important to note that when you call one of the Wait
methods, the runtime will check to see if the task you are waiting on has started executing. If task
has started executing, then the thread that called Wait
will block until task
has finished executing. However, if task
has not started running, then the runtime may execute the task using the thread that calls Wait
.
The various overloads and behaviors of Task.Wait
, Task.WaitAll
, and Task.WaitAny
are shown in the following table:
3.19.29.89