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...

Configuring Interprocess Synchronization

Wait handles can be shared between processes. The Mutexes in the previous two listings were local, meaning that they were only usable in one process a local Mutex is created when you use the default constructor. You can also create a named system Mutex, which is the kind that can be shared between processes. You do this by using the overloaded constructors that take a name argument. When using a named Mutex, it is important to see if the Mutex you are looking for has already been created,...

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...

Canceling Continuations

The techniques to handle cancellations for single Tasks, which we covered in the previous chapter, can be applied to continuations. The Task.ContinueWith , TaskFactory.ContinueWhenAll , and TaskFactory.ContinueWhenAny methods all have overloaded versions that accept a CancellationToken, which you can obtain by creating an instance of CancellationTokenSource. Listing 4-7 demonstrates canceling continuations. An antecedent Task is created and waits using a CancellationToken wait handle. When the...

Using Blocking Collection as IEnumerable

The BlockingCollection class can be used with foreach loops to allow consumers to safely take items from the collection. However, the input to the loop must be the result of the method and not the collection itself. If the collection is used, the foreach loop will immediately exit if it is executed before the first item has been added to the collection by the producer. The BlockingCollection class implements the IEnumerable lt gt interface, so the compiler will not generate an error for this...

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...

Writing an Orderable Contextual Partitioner

Having written a regular partitioner, it is a simple matter to create an orderable version. We won't go through this example member by member, because it is so similar to the previous listings. In fact, only four key things need to change to make our Partioner into an OrderablePartitioner. The first thing we have to change is the return types. Instead of returning enumerations of WorkItem, we are required to operate around instances of KeyValuePair lt long, WorkItem gt , where the long value is...

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...

Getting Loop Results

The result returned by the Parallel.For and Parallel.ForEach methods is an instance of the structure. ParallelLoopResult contains two properties that you can use to determine if Break or Stop was called. Table 5-4 summarizes the properties. Table 5-4. Properies of the structure Table 5-4. Properies of the structure Return true if all of the loop iterations were completed without Stop and Return the index of the lowest iteration in which the Break method was Listing 5-9 shows the use of the...

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...

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...