Using Classic Sleep

Because the TPL uses the classic .NET threading support behind the scenes, you can use the classic threading technique to put a Task to sleep. Call the static Thread.Sleep() method, and pass a time interval as an argument. Listing 2-14 reworks the previous example to use this technique. Listing 2-14. Sleeping Using Classic Threads create the cancellation token source CancellationTokenSource tokenSource new CancellationTokenSource() create the cancellation token CancellationToken token...

Determining If a Task Was Cancelled

You can determine if a Task has been cancelled by checking the IsCancelled property, which will return true if the Task was cancelled. Listing 2-12 demonstrates the use of this property. Listing2-12. Using the Task.isCancelled Property create the cancellation token source CancellationTokenSource tokenSource1 new CancellationTokenSource create the cancellation token CancellationToken token1 tokenSource1.Token create the first task, which we will let run fully Task task1 new Task gt...

Common Parallel Algorithms

In this chapter are 11 common parallel algorithms implemented using the TPL. You can download all of the source code for all of the algorithms from www.Apress.com. These are some of the most widely used building blocks in parallel programming, and I have included them as a reference for when you are facing a problem, a time-saver for when you need a quick answer, and a demonstration of how the TPL abstractions we covered throughout this book allow complex and rich functions to be developed with...

Using Wait Handles and the Mutex Class

Wait handles are wrappers around a Windows feature called synchronization handles. Several .NET synchronization primitives that are based on wait handles, and they all derive from the System.Threading.WaitHandle class. Each class has slightly different characteristics, and we'll walk through each of them in the next chapter when we explore coordinating Tasks. The wait handle class that has most relevance to avoiding data races and is System.Threading.Mutex. Listing 3-11 shows the basic use of...

Using the Reader WriterLock Slim Class

The System.Threading.ReaderWriterLockSlim class provides a convenient implementation of reader-writer locking that takes care of managing the locks. This class is a lightweight alternative for the heavyweight System.Threading.ReaderWriter, which Microsoft no longer recommends using. The lightweight version is simpler to use, offers better performance, and avoids some potential deadlocks. You acquire and release the ReaderWriterLockSlim read lock by calling the EnterReadLock and ExitReadLock...

Writing a Contextual Partitioner

The default partitioner and the chunking partitioner both operate on any data type. One advantage of writing a customer partitioner is that you can tailor your strategy to the data type that you need to process. This section will demonstrate how to implement a contextual partitioner and, in doing so, explain how to extend the Partitioner class to implement a custom technique. To start our partitioner, we need a context some data type with characteristics that we are going to specialize. I have...

Creating Manyto One and AnyToOne Continuations

The continuations we have seen so far have been one-to-one or one-to-many that is, one antecedent has one or more continuations. You can also perform many-to-one continuations using the ContinueWhenAll and ContinueWhenAny methods of the System.Threading.Tasks.TaskFactory class. You obtain an instance of TaskFactory through the static Task.Factory property. The ContinueWhenAll and ContinueWhenAny methods both take an array of Tasks argument. ContinueWhenAll schedules a continuation to be...

Member Description

QueueTask This method is called by the TPL when a Task has been created and TryExecuteTask This one is called by the scheduler to synchronously execute a Task that has been previously passed to the scheduler via the QueueTask method. The Task will not be executed if it is already executing or has already been executed. It returns true if the task was executed. TryExecuteTaskInLine This is called by the TPL to request that a Task be executed inline, and returns true if your scheduler executes...

Debugging Program State

The best approach is to use the Visual Studio debugger, which contains some very useful new parallel features to support parallel programming. To look at these features, we are going to use the code in Listing 7-4. This program has no useful value other than it causes a number of Tasks to call a number of methods to demonstrate the debugger features. The CountDownEvent is used so that the main application thread can wait until all of the Tasks have been created and scheduled. The SemaphoreSlims...

Using Spin Waiting

The spin waiting technique is included in this chapter for completeness, but I recommend against using it. When you use the other two sleep techniques, the thread that is performing your task gives up its turn in the schedule when its sleeping, so any other threads can have a turn. The scheduler, which is responsible for managing the threads running at any given time, has to do some work to determine which thread should go next and make it happen. You can avoid the scheduler having to do this...

Setting Parallel Loop Options

You can influence the behavior of parallel loops by supplying an instance of the ParallelOptions class as an argument to Parallel.For or Parallel.ForEach . There are three properties in ParallelOptions, and they are described in Table 5-2. Table 5-2. Properties of the System.Threading.Tasks.ParallelOptions class Table 5-2. Properties of the System.Threading.Tasks.ParallelOptions class Get or set a CancellationToken see the Canceling Parallel Loops section Get or set the maximum concurrency for...

Creating a Blocking Collection instance

The first step in the listing is creating the BlockingCollection, which I have done using the default constructor. The class is strongly typed, so I have had to declare the type that will be in the collection, in this case Deposit. BlockingCollection lt Deposit gt blockingCollection new The default constructor creates unbounded collections, which means that there is no limit to the number of outstanding work items in the collection. The producers can put items in the collection at a much faster...

Reading the Task Properties

An alternative to catching the exceptions is to use the properties of the Task class, in particular, the IsCompleted, IsFaulted, IsCancelled, and Exception properties. You still have to catch AggregateException when you call any of the trigger methods, but you can use the properties to determine if a task has completed, thrown an exception, or been cancelled, and if an exception was thrown, you can get the details of the exception. Listing 2-21 shows you how to use the Task properties. Listing...

Monitoring Cancellation with a Wait Handle

The third way to monitor task cancellation is to call the WaitOne method of the CancellationToken. WaitHandle property. I cover wait handles in depth later in this book, but for this chapter, it is enough to know that when you call the WaitOne method it blocks until the Cancel method is called on the CancellationTokenSource that was used to create the token whose wait handle you are using. Listing 2-9 demonstrates the use of the wait handle for cancellation monitoring. Two Tasks are created,...

Cancelling Tasks

One of the new areas of standardization in the TPL is cancelling tasks. This may seem like an odd thing to regard as useful, especially if you are accustomed to writing your own cancellation code using classic .NET threads. The new approach makes parallel code simpler and more consistent and reduces the risk of encountering some of the most commonly encountered problems when performing a cancellation, as you will see when we discuss putting a thread to sleep later in this chapter. Creating a...

Using Spin Locking

We encountered spinning in the last chapter. Typically, when waiting to acquire a regular synchronization primitive, your Task is taken out of the schedule waits until it has acquired the primitive and can run again. Spinning takes a different approach the Task enters a tight execution loop, periodically trying to acquire the primitive. Spinning avoids the overhead of rescheduling the Task because it never stops running, but it doesn't allow another Task to take its place. Spinning is useful if...

Concurrent Dictionary

The ConcurrentDictionary class implements a collection of key-value pairs. Like the other collection classes in the System.Collections.Concurrent namespace, ConcurrentDictionary provides methods whose names are prefixed with Try and returns bool results if they operate successfully. Table 3-9 describes the key members of the ConcurrentDictionary class. Table3-9. Key members of Try to add a new key-value pair to the collection. Return true if the pair was added successfully. Try to get the value...

Using Recursion and Upgradable Read Locks

Listing 3-15 separates the code that reads the shared data from the code that modifies it. Often, you will want to read data and make a change only if some condition is met. You could acquire the write lock to do this, but that requires exclusive access. Because you don't know in advance if you actually need to make changes, that would be a potential performance problem. But you are thinking, Aha I can acquire the nonexclusive read lock, perform the test, and then acquire the exclusive write...

Creating Child Tasks

A child Task, sometimes known as a nested Task, is one that is created inside the Task body of another. The Task in which the child is created is known as the parent. There are two kinds of child Task detached and attached. A detached Task, as demonstrated in Listing 4-10, has no special relationship with its parent the child will be scheduled and can be performed concurrently with the parent but has no impact on the parent itself. Create a new Task within the body of an existing one. Create a...

Performing Parallel Analysis with Visual Studio

Visual Studio 2010 includes the Concurrency Visualizer, which allows you to examine the behavior of your parallel program, albeit it with some significant limitations and frustrations. To use the Concurrency Visualizer, Visual Studio must be started with Administrator privileges. To do this, find Visual Studio in your Start menu, right-click it, and select Run as administrator. Load your project, and select Start Performance Analysis from the Debug menu. Note If you are running Windows 64-bit,...

Creating a Composite Cancellation Token

You can create a token that is composed from several CancellationTokens that will be cancelled if any of the underlying tokens is cancelled. You do this by calling the System.Threading. method and passing in the CancellationTokens that you want to link. The result is a new CancellationToken that you can use normally. Listing 2-11 demonstrates creating and using a composite cancellation token. Listing 2-11. Using a Composite Cancellation Token create the cancellation token sources...