As promised in my previous blog (Parallel Programming in .Net), we will get acquainted with diagnostics tools related to parallel development. Let us create a sample application, which we will use to debug.
- Open up your Visual Studio 2010
- Create a WPF application using the template provided by Visual Studio. I named my solution ParallelPattern. You can name it whatever you feel like.
- You should have four files in your project folder: App.xaml, App.xaml.cs, MainWindow.xaml and MainWindow.xaml.cs.
- Open MainWindow.xaml file and copy the code provided below into it:
<Window x:Class=”ParallelPattern.MainWindow”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Title=”MainWindow” Height=”350″ Width=”525″>
<Grid>
<StackPanel x:Name=”spBody” Orientation=”Vertical” Margin=”5px”>
<StackPanel x:Name=”spSearchTerm” Orientation=”Horizontal” Margin=”5px”>
<TextBox x:Name=”tbSearchTerm” MinWidth=”95px”/>
<Button x:Name=”bSearch” Content=”Search” Click=”SearchForNews”/>
</StackPanel>
<Separator Margin=”5px”/>
<StackPanel x:Name=”spSearchResult” Orientation=”Vertical” Margin=”5px”>
<TextBlock x:Name=”tbSearchResult”/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
- Open MainWindow.xaml.cs file and copy the code provided below into it:
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading.Tasks;
using System.Threading;
namespace ParallelPattern
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void SearchForNews(object sender, RoutedEventArgs e)
{
string sDir = @”C:\Users\akpandey\Desktop\NewsData”;
string sSearch = tbSearchTerm.Text;
//string sNewsItems = ParallelDirSearch(sDir, sSearch);
string sNewsItems = DirSearch(sDir, sSearch);
tbSearchResult.Text = sNewsItems;
}
private string DirSearch(string sDir, string sSearch)
{
StringBuilder sbFileList = new StringBuilder();
string[] directories = Directory.GetDirectories(sDir);
DateTime dtBegin = DateTime.Now;
Parallel.ForEach(directories, currentDirectory =>
{
string[] files = Directory.GetFiles(currentDirectory, “*.*”);
Parallel.ForEach (files, currentFile =>
{
StreamReader srFileText = new StreamReader(currentFile);
string sFileRead = srFileText.ReadToEnd();
srFileText.Close();
string sMatchExpression = sSearch;
if (Regex.IsMatch(sFileRead, sMatchExpression))
{
sbFileList.Append(System.IO.Path.GetFileName(currentFile) + Environment.NewLine);
}
});
DirSearch(currentDirectory, sSearch);
});
DateTime dtEnd = DateTime.Now;
TimeSpan tsTotalTime = dtEnd.Subtract(dtBegin);
sbFileList.Append(Environment.NewLine);
sbFileList.Append(tsTotalTime);
string sResult = sbFileList.ToString();
return sResult;
}
public string ParallelDirSearch(string sDir, string sSearch)
{
StringBuilder sbFileList = new StringBuilder();
string[] directories = Directory.GetDirectories(sDir);
DateTime dtBegin = DateTime.Now;
ParallelForEach<string>(directories, currentDirectory =>
{
string[] files = Directory.GetFiles(currentDirectory, “*.*”);
ParallelForEach<string>(files, currentFile =>
{
StreamReader srFileText = new StreamReader(currentFile);
string sFileRead = srFileText.ReadToEnd();
srFileText.Close();
string sMatchExpression = sSearch;
if (Regex.IsMatch(sFileRead, sMatchExpression))
{
sbFileList.Append(System.IO.Path.GetFileName(currentFile) + Environment.NewLine);
}
});
ParallelDirSearch(currentDirectory, sSearch);
});
DateTime dtEnd = DateTime.Now;
TimeSpan tsTotalTime = dtEnd.Subtract(dtBegin);
sbFileList.Append(Environment.NewLine);
sbFileList.Append(tsTotalTime);
string sResult = sbFileList.ToString();
return sResult;
}
public static void ParallelForEach<T>(IEnumerable<T> source, Action<T> body)
{
int iProcessors = Environment.ProcessorCount;
int remainingTasks = iProcessors;
using (var v = source.GetEnumerator())
{
using (ManualResetEvent mre = new ManualResetEvent(false))
{
for (int p = 0; p < iProcessors; p++)
{
ThreadPool.QueueUserWorkItem(delegate
{
while (true)
{
T nextItem;
lock (v)
{
if (!v.MoveNext()) break;
nextItem = v.Current;
}
body(nextItem);
}
if (Interlocked.Decrement(ref remainingTasks) == 0)
{
mre.Set();
}
});
}
mre.WaitOne();
}
}
}
}
}
- Create a folder named NewsData on your desktop or anywhere you prefer. Also, you can name your folder anything you like if you do not like the name NewsData.
- Create a few subfolders in the NewsData folder. Place some text files in those subfolders. If you like, you can grab some news items from an RSS feed to put in the text files.
- Go to the SearchForNews method inside MainWindow.xaml.cs file. Locate sDir string variable and replace its value with the actual path to the NewsData folder on your machine.
- Build your solution.
You should get the message ‘Build succeeded’. Now run the application by hitting F5 or Debug > Start Debugging from the debug menu. Your application should run and you should see the main window with a search box in it. Go ahead and click the Search button. The application will search all the folders, subfolders and the files at the specified root folder for the search term which is an empty string in this case and return the result below the horizontal line. Your window should look something like this:

In my NewsData folder there are three subfolders Africa, America and Asia.
- Africa folder contains two files Safrica.txt and Zimbabwe.txt.
- America folder contains two files Hiroshima.txt and Mexico.txt
- Asia folder contains two files China.txt and Skorea.txt
So, application ran and found empty string in all those files and returned the list of all those files. You can narrow the search by typing a text string in the search box. Keep in mind the search is case sensitive.
We will cover four diagnostic windows in this blog and they are Threads, Call Stack, Parallel Tasks and Parallel Stacks. To open these windows, go to the debug menu and follow the steps described below.
To open Threads window:
Debug > Windows > Threads or Ctrl+D, T
To open Call Stack window:
Debug > Windows > Call Stack or Ctrl+D, C
To open Parallel Tasks window:
Debug > Windows > Parallel Tasks or Ctrl+D, K
To open Parallel Stacks window:
Debug > Windows > Parallel Stacks or Ctrl+D, S
After opening all four diagnostic windows, your VS 2010 IDE should look something like the figure below:

You noticed that all diagnostic windows at the bottom of the VS 2010 IDE are blank. It is because all the threads related to this application completed their work and none of them are active.
Stop debugging. Go to DirSearch method in the MainWindow.xaml.cs file and locate following lines of code:
Parallel.ForEach(directories, currentDirectory =>
{
It should be in line 48 through 49. Place a break point at curly braces i.e. line 49. Start debuggin your application by hitting F5. Click on the search button once the main window is up. As soon as you click the search button, all four diagnostic windows should get populated. Now, your VS 2010 IDE should look something like the figure below:

At this point we can take a good look at these diagnostic windows one by one.
Threads window has following named columns: ID, Managed ID, Category, Name, Location and Priority. These are the default columns. You can expand this window for a better look if you like. You can add more columns by clicking on ‘Columns’ in the thread window’s toolbar. You should have one main thread and few worker threads visible in the thread diagnostic window. Notice a green square next to ‘Main Thread’ in the ‘Category’ column and a yellow arrow in one of the two unnamed columns. The yellow arrow in the thread window means a selected thread. If you double click on a different thread then the yellow arrow will move to that thread. Also, you notice that the contents in Call Stack, Parallel Tasks and Parallel Stacks windows change as well. The left most column lets you flag threads. Why would you want to flag threads? Well, it is because, on a large application, you will encounter quite a few threads and you would probably want to focus on a few threads of interest to you to avoid the clutter. To test the flag feature, go to the toolbar in the Parallel Stacks window and click on Show Only Flagged icon, you will notice that all the contents in the Parallel Stacks window disappeared. It is because we have no threads flagged in the thread window. Now go ahead and flag a few threads, you will notice that the stack frames for the flagged threads appear in the Parallel Stacks window instantly. You can toggle the Show Only Flagged mode.
Call Stack: Before we discus Call Stack window, it will be a good idea to briefly define what a call stack is. Call stack is a stack data structure which stores information about an active method. The main purpose of a call stack is to store the return address of a caller method. Once the callee finishes execution, it passes the control to the caller at the return address. Call stack also stores the parameters that need to be passed between caller and callee. There is usually one call stack associated with each thread or task. A call stack is made-up of stack frames. Stack frames contain information about a method’s state. Each call stack corresponds to a call to a method which has been called but not returned yet. This should provide us with enough background information on call stack. Make sure that the Main Thread is selected in the thread diagnostic window (Threads). Go ahead and expand the Call Stack diagnostic window for a better view. As you noticed, Call Stack has two columns – Name and Language and it has three records. Each record represents a stack frame. You should have something like this in the name column of the first row => ParallelPattern.exe!ParallelPattern.MainWindow.DirSearch.AnonymousMethod__0(string currentDirectory = “C:\\Users\\akpandey\\Desktop\\NewsData\\Africa”) Line 49. Note that the parameters are stored in the call stack. The yellow arrow indicates the active stack frame of the current thread.
Parallel Tasks: In .Net 4.0, tasks are the preferred API for writing parallel applications because they allow more scalable use of system resources and provide for more programmatic control than a thread. The Task Parallel Library, as its name implies, is based on the concept of tasks. The term task parallelism indicates one or more independent tasks running concurrently. A task represents an asynchronous operation and in many ways resembles a work item of a Thread or ThreadPool. However, a task is an abstraction at much higher level. Parallel Tasks diagnostic window allows us to view all the tasks running in parallel. You can use the flag column to filter the call stacks of the task in the Parallel Stacks window. To try it yourself, go to Parallel Stacks window and switch to Tasks view. The default view is Threads. Then, click on Show Only Flagged icon. You should see following message: Parallel Tasks window has no flagged items with call stacks. Now flag a task in the Parallel Tasks window, you will see its call stack instantly appear in the Parallel Stacks window. The yellow arrow indicates the current task. You can change the current task by double clicking on a task. When you double click a task, the yellow arrow moves from the previous position to current position but a white arrow appears in the previous position denoting the original task where the break took place. Parallel Tasks window has following default columns ID, Status, Location, Task, Thread Assignment and AppDomain. You can add or remove columns by right clicking any of the columns. Also, you can sort the record by clicking on any of the headers. Go ahead and right click on any of the headers and add a new column called Parent. This column indicates if the task has a parent. In our example, Task-2 is a parent of Task-1 and Task-3. That is why you see ‘2’ in the parent columns of Task-1 and Task-3. Another important column is Status. As the name implies, it shows the status of tasks. In our application, we have at the moment two running and one scheduled tasks. You can freeze a thread by taking following steps: select a task > right click > Freeze Assigned Thread. You can thaw a thread by selecting Thaw Assigned Thread.
Parallel Stacks is a very useful window for it has two view modes – Threads and Tasks. You can change the mode by selecting the desired mode from the drop down menu in the toolbar. Let us look at the Threads mode first. This is the default mode but go ahead and make sure that you are in the right mode by selecting ‘Threads’ from the drop down. You can expand the Parallel Stacks for a better view. You will notice that there are three boxes. They are labeled 5 Threads, 1 Thread and 1 Thread (number of boxes and its contents may vary on your computer because we are relying on .Net’s parallelization algorithm). You will notice that the two of the boxes have bolded blue borders. This means that both boxes contain the current thread. You can find this out by hovering over headers of both boxes. Hovering will display the list of threads; the current thread in the list is bolded. The call flow is depicted from bottom to up. You can change the call flow from options menu if you like. I will stick with the default flow for the time being. I had unpleasant experience trying to post the picture in my blog. So, I am going to stay away from the pictures. But I created an ad-hoc diagram below to show the call flow of one thread from another. I hope it is not too horrible.
External Code && Main Thread =>
{(Main Thread && DirSearch.AnonymousMethod_X)
(Worker Thread && DirSearch.AnonymousMethod_X)}
What the above diagram depicts in a nutshell is that the framework creates two instances of the anonymous method from DirSearch method. The first instance is seeded inside the Main Thread. The second instance is seeded inside a newly created Worker Thread.
You can switch the Parallel Stacks’ mode from Threads to Tasks. This will let you see the call stack for the Tasks. Just like Threads, hovering over the header of the box will let you view all the tasks that are in the box. You can view the stack frames by hovering over the call stack. In this sense, Tasks feel a lot like Threads.
Now, let us step into our code. As you step through the code, pay attention to all four diagnostic windows. You will notice that the yellow arrow in the Threads window is moving to keep up with the current thread and Call Stack window is updating stack frames as we step. By the time debugger hits line 53, we notice several changes in the Parallel Tasks window:
- Task-1 completed and is no longer visible in the Parallel Tasks
- Task-2 and Task-3 went to Waiting status
- And, we have two new tasks – Task-5 (Running) and Task-6 (Scheduled)
Keep stepping into the code and look at the flow of threads and tasks in the Parallel Stacks window. You will see threads going to sleep, waiting and joining. Also in the Parallel Stacks window, if you hover over call stack (either in Threads or Tasks mode), you will notice that the framework has assigned names to different instances of the anonymous method, e.g. AnonymousMethod_0, AnonymousMethod_1, etc. After numerous F11 key strokes, eventually the method returns and once that happens, all the windows except ‘Threads’ go blank. Because, we have no running tasks left.
I think this should be good enough an introduction to the topic of Parallel Diagnostic Tools. Now, it is time to dive into development of some parallel applications using Task Parallel Library (implemented as Task API) by Microsoft.