Watching Multiple Threads in C#

Exclusive offer: get 50% off this eBook here
C# 2008 and 2005 Threaded Programming: Beginner's Guide

C# 2008 and 2005 Threaded Programming: Beginner's Guide — Save 50%

Exploit the power of multiple processors for faster, more responsive software.

$23.99    $12.00
by Gastón C. Hillar | January 2009 | Microsoft

In order to solve problems that arise in concurrently running threads in applications, we need new debugging techniques suitable for the new parallelism environments that occur in Visual C#. In this article by Gastón C. Hillar, we will learn many tricks and debugging procedures that will help us find solutions to multithreaded application problems and have a better understanding of the execution of parallel threads. We will be performing the following exercises:

  • Learn some tricks to prepare multithreaded code to simplify the debugging and troubleshooting processes
  • Become skilled at watching and understanding the execution of multiple concurrent threads

We can use the BackgroundWorker component and then the Thread class to create new threads independent of the main application thread. The applications can respond to UI events, while the processing continues, and take full advantage of multiple cores, and can thus run faster. However, we are used to debugging applications that run in just one thread (the main thread), and there are many changes in the debugging process that generate great confusion when following the classic procedures running many concurrent threads. How can we successfully debug applications that are running many concurrent threads?

Time for action – Understanding the difficulty in debugging concurrent threads

Your cellular phone rings! The FBI agents have detected a problem with an encryption engine. When the application receives the same messages many times during a certain period, the encryption process generates exactly the same results, as shown in the following image:

Watching Multiple Threads in C#

Thus, hackers could easily break the code once they discover this important bug. They ask for your help. Of course, you want to cooperate because you do not want the FBI agents to get angry with you. However, you need to debug the multithreaded encryption engine, and you have never done that! Let's create a solution for this problem!

First, we are going to try to debug the multithreaded application the same way we do with a single-threaded application to understand the new problems we might face:

  1. Open the project, SMSEncryption.
  2. Define a breakpoint in the line int liThreadNumber = (int)poThreadParameter; in the ThreadEncryptProcedure procedure code.
  3. Press F5 or select Debug | Start Debugging in the main menu.
  4. Enter or copy and paste a long text (with more than 5,000 lines) in the Textbox labeled Original SMS Messages and click on the Run in a thread button. The line with the breakpoint defined is shown highlighted as the next statement that will be executed.
  5. Press F10 or select, Debug | Step Over in the main menu two or three times (depending on the number of cores you have in the computer). As you can see, the next statement that gets executed is the same even when you try to go on with the next one. It seems that the statement is not being executed. However, inspecting the value of poThreadParameter (the parameter passed to the ThreadEncryptProcedure procedure) shows that it changes each time you step over the statement, as shown in the following image:

    Watching Multiple Threads in C#

  6. Stop the application and repeat the steps 1 to 5 to make sure you are not crazy because of parallelism, multithreading, and the FBI agents!

What just happened?

You are getting nervous about the debugging process! Do not worry. We will learn how to debug your encryption engine while the FBI agents kindly prepare a cup of fresh cappuccino for you.

The debugger executed each new Thread class instance call to the Start method, with this line:

prloThreadList[liThreadNumber].Start(liThreadNumber);

Then, it entered in the ThreadEncryptProcedure method (we have used the same method for every created encryption thread) with different values for the poThreadParameter parameter. Therefore, you stayed in the same statement as many times as the threads were created (equivalent to the number of cores available in the computer) in the following line:

int liThreadNumber = (int)poThreadParameter;

As we can see, debugging this way is very confusing, because the IDE switches from one thread to another, and you loose control over the statements that are going to be executed next. In a debugging process, you need to know in which part of the application you are.

As we tested our first attempt to debug a multithreaded application, we tried the same technique as with single-threaded applications. There are new subjects to learn and new techniques to use.

Debugging concurrent threads

When we need to inspect values, execute a procedure step-by-step, and find solutions to problems related to some specific code, the best way to achieve that with a multithreaded application is to work with it as a single-threaded application. But, how can we do that? It is very simple. We must run one thread at a time and freeze the other concurrent threads while we are debugging the thread in which we are interested and on which we are focusing.

When we debug single-threaded applications, we are aware of the method in which we are positioned and its context. In multithreaded applications, we must also be aware of the thread in which we are positioned. If we do not know in which thread we are executing statements, we will be completely confused in just a few seconds, as happened in our previous activity.

We must tailor our multithreaded applications to simplify the debugging process. If we do not do this, the debugging process will be a nightmare. Indeed, we do not want that to happen!

Time for action – Finding the threads

You wonder where the threads are. How can you guess in which thread you are working while executing the application step-by-step? You are an excellent C# programmer, but multithreaded debugging is very confusing. You do not want the FBI agents to realize that you are in trouble. However, you must hurry up, because they have a great training in detecting nervous people in the course of their usual interrogations.

Now, we are going to use the IDE features to help us find the threads in a multithreaded application:

  1. Using the same project that we used in the previous example, with the same breakpoint defined, press F5 or select Debug | Start Debugging in the main menu.
  2. Enter or copy and paste a long text (with more than 5,000 lines) in the Textbox labeled Original SMS Messages and click on the Run in a thread button. The line with the breakpoint defined is shown highlighted as the next statement that will be executed.
  3. Select Debug | Windows | Threads in the main menu or press Ctrl + Alt + H. The Threads window will be shown, displaying all the threads created by the application process, as shown in the following image:

    Watching Multiple Threads in C#

  4. The yellow arrow in the left of the thread list points out the current thread—the thread for which the IDE is showing the current statement.
  5. Press F10 or select Debug | Step Over in the main menu. As you can see, the next statement is the same again, but the current thread pointed out in the thread list changes, as shown in the following image:

    Watching Multiple Threads in C#

  6. Go on running the application step-by-step and watch how the current thread changes. Observe the Threads window throughout your debugging process.

What just happened?

You found the threads in the debugging process. Now, you believe you will be able to make the necessary changes to the application if you learn a few debugging techniques quickly.

The Threads window displays the list of threads created by the application process. Many of them are created automatically by the C# runtime. The others are created by the Thread class instances and the BackgroundWorker component we have in the application.

Using the Threads window, we can easily determine in which thread we are executing when debugging a multithreaded application. It is indeed very helpful.

Remember that each thread has its own stack.

 

C# 2008 and 2005 Threaded Programming: Beginner's Guide Exploit the power of multiple processors for faster, more responsive software.
Published: January 2009
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

 

Understanding the information shown in the Threads window

The Threads window displays the following informati on for each thread:

  • ID: A unique numeric thread identifier.
  • Name: The thread's name (the Name property). If the thread's Name property was not assigned, it has a null value, and the window will show <No name> in this column, as shown in the following image:

    Watching Multiple Threads in C#

  • Location: The method the thread is running. In the previous image, the thread with its Location presented as SMSEncrypti on.Program.Main is the main thread and the threads with their Location set as SMSEncryption.frmSMSEncryptionEngine.ThreadEncryptProcedure are the ones created as instances of the Thread class by our dynamic thread-manufacturing algorithm.
  • Priority: The priority assigned to the thread. The possible values are similar to the ones learned and experienced for the processes.

    No matter what the priority settings are, the results always depend on the scheduler decisions based on the number of running threads and their resources usage.

  • Suspend: A bool value indicating whether the thread is running or paused. A 0 means the thread is running and a 1 means that it is suspended. When a thread is suspended, a pause icon is shown on the left, as shown in the following image:

Watching Multiple Threads in C#

The problem with our applications is that we did not use names for the threads, and they are using the same method (ThreadEncryptProcedure). We have to find a remedy for this.

Time for action – Assigning names to threads

You must identify each thread in the Threads window. This way, you will be able to easily find the problems in the encryption engine without getting confused.

Now, we are going to make some changes in the Thread class instances creating code, and to the BackgroundWorker in order to simplify the thread identification process during debugging:

  1. Stay in the project, SMSEncryption.
  2. Open the Click event in the button butRutRunInThread, and add the following code at the beginning:
    // Give the main thread a name
    Thread.CurrentThread.Name = "Main thread";
  3. Add the following line of code before starting each thread with the line prloThreadList[liThreadNumber].Start(liThreadNumber); in the for (liThreadNumber = 0; liThreadNumber < priProcessorCount; liThreadNumber++) loop, in the Click event handler in the button butRunInThread:
    // Give the thread a name
    prloThreadList[liThreadNumber].Name = "Encryption #"
    + liThreadNumber.ToString();
  4. Open the DoWork event in the BackgroundWorker bakShowEncryptedStrings and add the following code at the beginning:
    // Give the BackgroundWorker thread a name
    Thread.CurrentThread.Name = "bakShowEncryptedStrings";
  5. Keep the breakpoint we defined in the previous example.
  6. Define a new breakpoint in the line priLastEncryptedStringShown = 0; in the BackgroundWorker bakShowEncryptedStrings DoWork event.
  7. Press F5 or select Debug | Start Debugging in the main menu. Make sure the Threads window is visible.
  8. Enter or copy and paste a long text (with more than 30,000 lines) in the Textbox labeled Original SMS Messages and click on the Run in a thread button. The line with the breakpoint defined in the ThreadEncryptProcedure procedure is shown highlighted as the next statement that will be executed. But, the threads are easily identified by their names in the Threads window, as shown in the following image:

    Watching Multiple Threads in C#

  9. Press F5 or select Debug | Start Debugging in the main menu many times until you reach the breakpoint defined in the BackgroundWorker code. You will see a new thread with the bakShowEncryptedStrings name defined, as shown in the following image:

    Watching Multiple Threads in C#

  10. Go on running the application step-by-step and watch how the current thread changes. Observe the Threads window throughout your debugging process.

What just happened?

Now, you can easily identify each thread in the Threads window. The only thing you need is to isolate one thread, to understand what is going on in the encryption process.

Before starting with the threads, we assigned them a name. We did that for the main thread, the BackgroundWorker thread, and the encryption threads. Thus, the Threads windows showed their names, and we can take control of the concurrent threads.

The following line assigns a string value to the Name property of the Thread class instance, taking into account the thread number (remember that we are creating them dynamically according to the number of available cores):

prloThreadList[liThreadNumber].Name = "Encryption #"
+ liThreadNumber.ToString();

If we have four cores available, the resulting names will be the following:

  • Thread #0: "Encryption #0".
  • Thread #1: "Encryption #1".
  • Thread #2: "Encryption #2".
  • Thread #3: "Encryption #3".

It is a good practice to give each thread a name. It is very important to simplify the debugging process and to share code with other developers.

Identifying the current thread at runtime

A Thread class instance provides access to the Name property. As mentioned earlier, it allows us to set the name, and it is shown in the Threads windows. Nevertheless, the BackgroundWorker does not provide a direct method or property to set the name of the thread it creates.

For that reason, we use the CurrentThread property of the Thread (System.Threading.Thread) class. It offers access to a Thread instance of the currently running thread, that is, the thread running the current method. As it is an instance of the Thread class, it has a Name property.

The following line accesses the current thread of the BackgroundWorker and assigns the name for that thread, through Thread.CurrentThread:

Thread.CurrentThread.Name = "bakShowEncryptedStrings";

The current thread is the one created by the BackgroundWorker as we are in the DoWork event handler code. This is shown in the following image:

Watching Multiple Threads in C#

 

Be careful with the BackgroundWorker because the ProgressChanged event handler code runs in the main thread and not in the thread created by the BackgroundWorker.

The following line accesses the current thread (the main thread) and assigns the name for that thread, again using Thread.CurrentThread:

Thread.CurrentThread.Name = "Main thread";

Of course, we can also use Thread.CurrentThread in the ThreadEncryptProcedure to assign the names for each created thread as the first instruction, instead of doing it before calling the Start method, as shown in the following line:

Thread.CurrentThread.Name = "Encryption #" + ((int)poThreadParameter).
ToString();

Thread.CurrentThread can also be used to access the current thread properties and methods. For example, we can access the IsBackground property with the following expression:

Thread.CurrentThread.IsBackground

Then, we can evaluate it for any purpose.

We can also evaluate the Name property of the current thread in order to execute conditional code, according to the thread. Identifying threads offers new opportunities in multithreaded applications because we are able to know in which thread the code is being executed at runtime. Moreover, it allows us to understand what is going on while we are debugging. It is too difficult to debug complex multithreaded code successfully without using names to identify each thread.

Summary

In this article, we covered how to prepare the multithreaded code to simplify the debugging and troubleshooting processes using names for the threads to identify them in the IDE. We interpreted the information shown in the Threads window.RunWorkerAsync method. Basically, we performed the following tasks:

  • Understanding the difficulty in debugging concurrent threads
  • Finding the threads
  • Assigning names to threads

In the next article we will see how to Debug Multithreaded Applications as Singlethreaded Applications in C#

C# 2008 and 2005 Threaded Programming: Beginner's Guide Exploit the power of multiple processors for faster, more responsive software.
Published: January 2009
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

About the Author :


Gastón C. Hillar

Gastón C. Hillar has been working with computers since he was eight. He began programming with the legendary Texas TI-99/4A and Commodore 64 home computers in the early 80s.
He has a Bachelor degree in Computer Science from which he graduated with honors, and an MBA from which he graduated with an outstanding thesis. Now, he is an independent IT consultant and a freelance author always looking for new adventures around the world.

To date he’s written more than 40 books in Spanish, and for Packt Publishing has written “C# 2008 and 2005 Threaded Programming: Beginner's Guide”. He usually writes articles for Spanish magazines Mundo Linux, Solo Programadores and Resistor.
He contributes to Dr. Dobb's Go Parallel programming portal http://www.ddj.com/go-parallel/ and he is a guest blogger at Intel Software Network http://software.intel.com

Gastón C. Hillar is the author of "Microsoft Silverlight 4 and SharePoint 2010 Integration".

Books From Packt

Programming Microsoft® Dynamics™ NAV
Programming Microsoft® Dynamics™ NAV

Quality Assurance for Dynamics AX-Based ERP Solutions
Quality Assurance for Dynamics AX-Based ERP Solutions

Implementing Microsoft Dynamics NAV 2009
Implementing Microsoft Dynamics NAV 2009

ASP.NET 3.5 Social Networking
ASP.NET 3.5 Social Networking

Software Testing with Visual Studio Team System 2008
Software Testing with Visual Studio Team System 2008

ASP.NET 3.5 Application Architecture and Design
ASP.NET 3.5 Application Architecture and Design

Active Directory Disaster Recovery
Active Directory Disaster Recovery

Entity Framework Tutorial
Entity Framework Tutorial

 

 

 

 

Your rating: None Average: 5 (2 votes)
Nice post by
Very nice to read such "old" posts! This topic, like the little that you can see, they feel accompanied us at the beginning
Hoping to have my say by
Hey - I am definitely happy to discover this. cool job!
Looking Forward To Getting Involved by
Thanks...this looks really interesting. I am looking forward to having my says!

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
e
p
a
k
G
5
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software