Visual Studio 2010 Brings Parallelism Mainstream

Steve Teixeira is the Product Unit Manager for Parallel Developer Tools at Microsoft.

Parallel computing is not a new problem. For well over 40 years, academia, government, and industry have relied on parallel computing to solve the day's most computation- and data-intensive problems. At the same time, software developers have been struggling to harness this computing power while managing the complexity inherent in writing parallel programs. Despite this, the task of making parallel development easy is by no means a solved problem. Skeptics may ask, "why is so much energy being expended today to mitigate such an old and well-trodden problem?"

While parallel machines of yesteryear may have been constructed of enchanted metals and powered by unicorn tears, today's parallel machines are as common -- and nearly as inexpensive -- as hamburgers. Blame science for the commoditization of parallel computing hardware. The physics of modern CPU architectures is such that heat generation and power consumption become increasingly untenable problems as clock frequencies rise. As clock frequencies and sequential execution performance have reached a near-plateau, CPU manufacturers are increasing core counts to ensure the computational throughput of CPUs continues to increase at a steady clip. But, ay, there's the rub: Software developers must enthusiastically embrace parallelism in order to realize the performance benefits that modern, multicore hardware has to offer.

In other words, parallel hardware has gone mainstream and so, too, must developer tools. To this end, Visual Studio 2010 contains a raft of new innovations in the parallel computing space intended to enable developers to cope with the complexities of writing, retrofitting, and diagnosing parallel applications. These technologies occupy several levels in the programming tools stack, from core execution platform to programming models and libraries to debugging and profiling tools.

Figure 1: The Visual Studio 2010 Parallel Development Stack

Task-based Parallelism

Visual Studio 2010 and .NET 4 introduce task-based parallel programming models for both native- and managed-code developers. While the Win32 and .NET thread-based programming models have served us well for many years, threads require developers to think in terms of execution flow, to essentially adapt their code to fit the execution models of the underlying OS and hardware. Tasks, on the other hand, let developers think in terms of the logical chunks of work within their program, which tends to more closely approximate how we naturally think about our programs already. Learning to effectively use the task-based programming models is often less about learning a new kind of abstraction and more about unlearning old, less effective patterns.

The managed parallel programming model library in Visual Studio 2010 is referred as the Task Parallel Library (TPL), and the Visual C++ library is called the Parallel Pattern Library (PPL). From a conceptual standpoint, TPL and PPL are more alike than different, so I describe them together, calling out differences where appropriate.

Tasks are abstracted by .NET's Task class in TPL and by the task_handle class in PPL. Creating a new task to perform some operation in parallel in C# looks something like this:

Task t = new Task(() => DoWork());
t.Start();

or, equivalently:

Task t1 = Task.Factory.StartNew(() => DoWork() );

Note the use of the lambda expression to express the parallel work to be done, which helps make the Task-based programming models feel like an integrated part of the language. The C++ analog to the above concept would look something like this:

One difference between native and managed code revealed by the above examples is the task_group class used in PPL. task_group is a sort of container class to manage one or more logically related task_handle instances, enabling the tasks to be dealt with as a group. TPL, on the other hand, does not have this level of abstraction, and favors static methods of the Task and TaskFactory classes for managing tasks.

In each of the above cases, the parallel work to be executed is the contents of the DoWork() function. A slightly more real-world use of this pattern is to implement a quick sort routine using divide-and-conquer parallelism instead of the typical single stack recursion method:

The call to task_group::wait() method in the above example waits for the tasks in the group to complete, joining them with the caller. Tasks have several advantages over thread-centric programming models, including the ability to wait for completion of a task, cancel tasks in-flight, and leverage the benefits of exception handling in parallel code. TPL further has the ability to compose multiple tasks together using continuations and to establish parent-child relationships between tasks.

TPL's continuations are a particularly powerful concept, enabling tasks to be wired together such that one task can begin as soon as another finishes. The following code sample shows how one task can be launched to do some parallel work with another task automatically launched after its completion:

If you're in the market for a simpler abstraction, it's also possible to fork off parallel work without dealing directly with tasks. Pass a few lambda functions to the Parallel.Invoke() method in TPL or the parallel_invoke() function in PPL, and you have the ability to "fire and forget" parallel work items:

Parallel loop constructs represent an even simpler way to enjoy the benefits of parallelism. The pattern is simply to replace a for or foreach loop with a parallel version of the same. The parallel versions will divide loop iterations into tasks and execute them as with any other TPL or PPL parallel tasks, as in the C# code below:

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Video

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!