Waiting for tasks to finish

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.

How to do it…

Let's create a Console application that demonstrates how to wait for task completion.

  1. Launch Visual Studio 2012.
  2. Start a new project using the C# Console Application project template, and assign WordCount as the Solution name.
    How to do it…
  3. Add the following using statements at the top of your Program class:
    using System;
    using System.Linq;
    using System.Net;
    using System.Threading.Tasks;
  4. In the 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)";
  5. OK, now let's create our first task. This task will use 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());
        }
    );
  6. Now, just below the previous task, write the following statements to wait on the task, and write a message to the Console application:
    task1.Wait();
    Console.WriteLine("Task 1 complete. Creating Task 2 and Task 3.");
  7. Below the previous statement, enter the code to create the second and third tasks. These tasks are very similar to the first task.
    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());
    });
  8. Finally, let's use 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();
  9. In Visual Studio 2012, press F5 to run the project. You should see output similar to the following screenshot. Note that the exact order of the last few lines of text may still vary depending on the execution order of the second and third tasks.
    How to do it…

How it works…

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:

Wait()

Waits for the task to complete execution.

Wait(CancellationToken)

Waits for the task to complete execution or CancellationToken to be set.

Wait(Int32)

Waits for task to complete or number of milliseconds to pass. A value of -1 waits indefinitely.

Wait(TimeSpan)

Waits for the task to complete execution or specified timespan to pass.

Wait(Int32, CancellationToken)

Waits for task to complete, number of milliseconds to pass, or CancellationToken to be set.

WaitAll(Task[])

Waits for all of the tasks in array to complete execution.

WaitAll(Task[], Int32)

Waits for all of the tasks in the array to complete execution or number of milliseconds to pass. A value of -1 waits indefinitely.

WaitAll(Task[], CancellationToken)

Waits for all of the tasks in array to complete execution or for a CancellationToken to be set.

WaitAll(Task[], TimeSpan)

Waits for all of the tasks in array to complete execution or specified timespan to pass.

WaitAll(Task[], Int32, CancellationToken)

Waits for all of the tasks in array to complete execution, number of milliseconds to pass, or CancellationToken to be set.

WaitAny(Task[])

Waits for any of the tasks in the array to complete execution.

WaitAny(Task[], Int32)

Waits for any of the tasks in array to complete execution or number of milliseconds to pass. A value of -1 waits indefinitely.

WaitAny(Task[], CancellationToken)

Waits for any of the tasks in array to complete execution or for a CancellationToken to be set.

WaitAny(Task[], TimeSpan)

Waits for any of the tasks in array to complete execution or specified timespan to pass.

WaitAny(Task[], Int32, CancellationToken)

Waits for any of the tasks in array to complete execution, number of milliseconds to pass, or CancellationToken to be set.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.19.29.89