Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Threading Support in the .NET Framework

To provide a great user experience applications need to do a lot of thingsmany of them seemingly at the same time. Professional applications do this using multi-threading. Until recently however, creating true multi-threaded applications wasn't a simple task and wasn't available to most developers. Thankfully, multi-threading is a fundamental feature of the .NET Framework and developers can write multi-threaded applications with relative ease, no matter whether they use managed C++ code, C#, VB.NET, or any other .NET language.

he .NET Framework introduces advanced free threading as a fundamental building block. The Framework offers solutions even for advanced issues, enabling developers to build truly thread-safe applications in a relatively simple fashion. This makes multi-threading available to all .NET developers, no matter what language they choose to implement their solutions.

What Is Multi-Threading?
In simple terms, multi-threading is the ability to run different pieces of code (methods) seemingly at the same time. One can imagine multi-threading like multi-tasking within a single application.

Of course, computers generally cannot do multiple things at the same time (unless you're talking about a multi-processor system). Instead, different tasks and threads have to share processing resources and the operating system assigns "time slices" to different tasks and threads in a round-robin fashion.

You can use multi-threading for a variety of scenarios. A simple example is Internet Explorer: Whenever one uses IE to navigate to a Web site, the download engine is busy retrieving information from the web site. However, while information downloads, the user interface is "alive" and ready to be used. The user can move the window around, resize it, and if parts of the page have already been downloaded they can scroll up and down in the part of the page that has already been rendered. The reason one can use the interface while downloading and rendering is still in progress is that all these things run on separate threads. Presumably there is a thread for the interface, a thread for downloading information, and a rendering thread (and perhaps others that are not as obvious). If all these things were done on the same thread, the user would have to wait for a page to download completely and then render before they could browse to a different site or even close the window.

Another multi-threading example is the background spell checker that serves me quite well while I am typing text into MS Word. As I type, Word silently checks my spelling and highlights spelling mistakes as I go. This feature does not interrupt my typing no matter how quickly I type. Spell checking happens on a separate thread (probably on a background thread—a thread of lower priority—ensuring that it will not take away too much processing time from the main application thread).

Most readers are not about to implement their own Web browsers or text processing applications, but how about an auto-complete textbox that finds matching values in a database while the user types? (You can see similar behavior in Internet Explorer when you enter a URL in the address bar.) You wouldn't want to interrupt the user while they're typing, so a task like this is best performed using a separate thread.

Or how about background verification of data entry forms? Instead of verifying entries when the user tabs out of a textbox (or other control), which is very interruptive if the logic is complex and perhaps data intensive, this could be done on a background task using a lower priority thread.

Implementing a Simple Example
So how do you go about creating your own threads? The basic idea is to create a Thread object based on the Thread class that you'll find in the System.Threading namespace. Consider the following VB.NET example:

Imports System.Threading Public Class SlowClass Public Sub DoSomething() Me.DoSomethingSlow() MsgBox("Done!") End Sub Public Sub DoSomethingSlow() ' Imagine some slow code here... Thread.Sleep(10000) End Sub End Class

This code simulates a slow operation. It doesn't do anything with multi-threading despite the inclusion of the System.Threading namespace. I simply use Thread.Sleep() to put the main application thread to sleep for 10 seconds, which simulates a slow process.

When the DoSomething() method is called it will immediately branch out to the DoSomethingSlow() method. This method will take 10 seconds to execute before it returns control to the first method, which will ultimately display a message box.

If you instantiate this object and call it from a Windows form, the form will be non-responsive for 10 seconds. The form cannot be moved, resized, or closed. In fact, if you switch to a different task and then back to your form, the form will even fail to repaint itself.

Now let's look at the same example in a multi-threaded fashion:

Imports System.Threading Public Class SlowClass Public Sub DoSomething() Dim oThread As New _ Thread(AddressOf Me.DoSomethingSlow) oThread.Start() MsgBox("Done!") End Sub Public Sub DoSomethingSlow() ' Imagine some slow code here... Thread.Sleep(10000) End Sub End Class

Here I've made a fairly simple change—I create a new Thread object and point it to the address of the DoSomethingSlow() method, which I then pass to the object's constructor as I create it. This provides the thread information about what I'd like it to execute. Now all that's left is to start the thread that will execute the method on a separate thread.

When you run this example you'll notice that it displays the message box instantaneously because the DoSomething() method doesn't wait for the DoSomethingSlow() method to complete. Instead, the DoSomethingSlow() method runs on its own thread entirely independent from the main thread. This allows the first thread to continue with the next line of code right away.

Note that both threads run truly independent from each other. Not only does the message box not have to wait for the slow method to complete, but the slow method is equally independent from the first method and proceeds on its 10 second quest no matter how long the message box stays up. You can easily verify this by adding another message box to the slow method:

Public Sub DoSomethingSlow() ' Imagine some slow code here... Thread.Sleep(10000) MsgBox("Slow Method Done!") End Sub

Of course, you can write the same example in C# as well:

using System.Threading; public class SlowClass { public void DoSomething() { ThreadStart oTS = new ThreadStart(this.DoSomethingSlow); Thread oThread = new Thread(oTS); oThread.Start(); MessageBox.Show("Done!"); } public void DoSomethingSlow() { // Imagine some slow code here Thread.Sleep(10000); } }

Note that there is a slight difference between the C# and the VB.NET example! In C#, you cannot just point the Thread object at the address of a method. Instead, you have to generate a ThreadStart delegate (see sidebar "Delegates" for more information on this subject) that points to the slow method. You then proceed to pass that delegate to the Thread object and start it the same way you did in the VB.NET example.

Note that the two languages don't really differ very much. VB.NET allows you to take a shortcut through the AddressOf operator. In fact, it would have been perfectly fine to use the ThreadStart delegate in VB.NET (and it provides more flexibility in many cases):

Public Sub DoSomething() Dim oTS As New ThreadStart( _ AddressOf Me.DoSomethingSlow) Dim oThread As New Thread(oTS) oThread.Start() MsgBox("Done!") End Sub

At this point VB.NET developers may point out that their language is more productive since the ThreadStart object is optional. C# enthusiasts on the other hand would promote the fact that no AddressOf operator is required in their language. I will remain neutral on the subject.

(See Sidebar: Pre-Emptive vs. Cooperative Thread Switching)

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date