Quick Guide to .NET Framework Task Parallel Library Visual Studio 2010 Debugger

Debugging is a frustrating experience.B The last thing a
developer needs is insufficient debugging support or difficulties operating the
Debugger.B Visual Studio has had intuitive debugging facilities for some
time now.B However the advent of Parallel Computing capabilities like the .NET
Framework
Task
Parallel Library
has introduced a twist on debugging.B

Old debugging tools and techniques just don’t cut it in the
new Parallel
Computing
world.B Parallel applications are doing too many things at
once.B Pausing on a breakpoint and stepping through code is not enough.B
Developers need to know more about their application than they ever have before
or Parallel Computing will forever be a niche approach.

When Microsoft released Visual Studio 2010 and
unleashed Parallel Computing; they included a first-class Parallel Debugger.B
This article is a short guide to using the Debugger to debug an application
built on the .NET Framework Task Parallel Library.B I’m going to
demonstrate how the Parallel Debugger works by walking you through a
running sample application.

Getting Started with Parallel Tasks

The whole sample application appears below.

Task temp = null;

var t1 = Task.Factory.StartNew(() =>
{
    Thread.CurrentThread.Name = "Iamt1";
    while (true) {Thread.Yield();}
},
TaskCreationOptions.LongRunning);

var t2 = Task.Factory.StartNew(() =>
{
    Thread.CurrentThread.Name = "Iamt2";
    while (true){Thread.Sleep(100);}
},
TaskCreationOptions.LongRunning);

var tN = new Action<object>[5];
tN[0] = new Action<object>(val => { object n = val; while (true) { Thread.CurrentThread.Name = "IamtN[" + n.ToString() + "]"; Thread.Sleep(500); } });
tN[1] = new Action<object>(val => { object n = val; while (true) { Thread.CurrentThread.Name = "IamtN[" + n.ToString() + "]"; Thread.Sleep(500); } });
tN[2] = new Action<object>(val => { object n = val; while (true) { Thread.CurrentThread.Name = "IamtN[" + n.ToString() + "]"; Thread.Yield(); } });
tN[3] = new Action<object>(val => { object n = val; while (true) { Thread.CurrentThread.Name = "IamtN[" + n.ToString() + "]"; Thread.Yield(); } });
tN[4] = new Action<object>(val => { object n = val; while (true) { Thread.CurrentThread.Name = "IamtN[" + n.ToString() + "]"; Debugger.Break(); } });

for (int n = 0; n < 5; ++n) {temp = Task.Factory.StartNew(tN[n], n, TaskCreationOptions.LongRunning);}

Console.WriteLine("Any key to quit...");
Console.ReadKey();

The code is almost trivial; two separate Tasks are started
and a Task array is started.B Tasks are set to long running and execute either
a Yield or Sleep.B The choice of Yield or Sleep will be explained later in the
article.

If you copy the code above to a Console Application you'll
need to include the following namespaces.

  • System.Threading is required for the Thread class access.
  • System.Threading.Tasks is required for Task classes.
  • System.Diagnostics is required to interact with the Debugger.

Thread.CurrentThread gives a developer access to properties
of the thread running the current piece of code.B For reasons I'll explain
later, each Task assigns the Name property of its current thread.

The Debugger.Break() method halts application execution.B
Including the method is like adding a permanent breakpoint in your application.B
When the application executes, it will break on the Debugger.Break method; the
debugger will spring into action and expose some additional functionality.

Parallel Tasks Overview

The debugger is aware of an application's Tasks and
Threads.B Since this introduction deals with the Task Parallel Library, I'm
going to drill into the Task debugging experience.

Viewing executing Task information is not enabled by
default.B Selecting "Parallel Tasks" from the Debug Window menu enables the
Parallel Tasks viewing.

Parallel Tasks Viewing
Figure 1: Parallel Tasks Viewing

Once Parallel Tasks is open a developer is free to navigate
between all created Tasks.B Double-clicking a Task in the viewer takes the
developer to the currently executing line of code.

Task Navigation
Figure 2: Task Navigation

As you may have noticed, there is some interesting
information available in the Parallel Tasks Window.

Parallel Tasks Detail

A screen shot of the Parallel Tasks Window appears below.

Parallel Tasks Dashboard
Figure 3: Parallel Tasks Dashboard

Task Status will vary depending on the state of the Task,
though typically, a Task Status will be "Running" or "Waiting".B In the
example, all Tasks with a Yield are shown with a Running Status.B Tasks that
are "Sleeping" are shown "Waiting".B There are other Statuses; however, a
complete review of Statuses is beyond the scope of this article.

The sample assigns the CurrentThread.Name property, so the
assigned Name appears in the Name column.B Underlying an executing Task is a
Thread plucked from the Threadpool.B For the duration of time a Task is
executing, it essentially owns the Thread allocated to it.B As you may have
observed, assigning the name makes it easy to distinguish between the Threads.

Conclusion

Parallel computing features like the Task Parallel Library puts
new Debugger demands on a development tool.B New Debugger features in Visual
Studio 2010 meets these new demands.B This was a demonstration of using these
new features to Debug an application built on the Task Parallel Library.B This
article was a quick introduction.B There are many more features that are beyond
the scope of this article.B You'll find more comprehensive resources at the end
of the article.

Resources

Debugging Task-Based Parallel Applications in Visual Studio 2010

The Moth: Parallel Tasks - new Visual Studio 2010 debugger window

Channel 9: Parallel Tasks - new Visual Studio 2010 debugger window

Parallel Development in Visual Studio

More by Author

Must Read