Search:
Locator+ Code:
FTPOnline Channels Conferences Resources Hot Topics Partner Sites Magazines About FTP RSS 2.0 Feed
 

Power Threading in the .NET Framework
Use the system thread pool to create more efficient multithreaded applications.
by Jon Rauschenberger

VSLive! Orlando, September 18, 2002

Note: Jon Rauschenberger is presenting "Threading with .NET" on Wednesday, September 18, at VBITS Orlando. This tip is taken from the material for that session.

The .NET Framework exposes power threading tools to all developers—regardless of the language they're using. For the first time, VB developers can easily create multithreaded applications that take full advantage of the Windows platform's threading capabilities. Taking advantage of this functionality is relatively simple. For example, consider this class:

Public Class Worker

    Public Sub DoSomeWork()
        Thread.Sleep(1000)
    End Sub

End Class

This simple class exposes a single method that simulates a long-running piece of work by sleeping the active thread for one second. If you need to call this method multiple times, you will benefit by spawning multiple threads and running those calls on separate threads. All the classes you need to write multithreaded code are in the System.Threading namespace. To use these classes, import that namespace with this code:

Imports System.Threading

If you needed to call the DoSomeWork method 100 times, you could use this code:

        For currentWorkItem = 1 To 100

            Dim currentWorker As New Worker()
            Dim currentThreadStart As New _
               ThreadStart( _
               AddressOf currentWorker.DoSomeWork)
            Dim newThread As New _
               Thread(currentThreadStart)
            newThread.Start()

        Next

This will spawn a new thread for each request and then run the DoSomeWork method in the thread. The problem with this code is that you are spawning 100 threads to process the 100 calls. Spawning more than approximately 25 threads per CPU leads to significant inefficiencies. When multiple threads are executing, the operating system has to schedule processor time for each thread. The more threads you spawn, the more time the OS must spend scheduling CPU time for each thread, and the less time the CPU spends executing the work each thread is doing.

To get around this issue, the .NET Framework provides a system thread pool that you can queue work into. The thread pool is a pool of threads that process requests off an internal work queue. The maximum number of threads in the pool defaults to 25 per CPU. This means that regardless of how many requests you drop on the work queue, there will never be more threads spawned than the number of CPUs times 25. To use the system thread pool to call the DoSomeWork method 100 times, you use the ThreadPool.QueueUserWorkItem method. This method takes a delegate as an input parameter. When the item is pulled off the queue by one of the worker threads, the thread will call the delegate and your code will execute.

The first step in using the system thread pool is to create the method you want the thread to execute with this code:

    Private Sub CallDoWork(ByVal State As Object)
        Dim currentWorker As New Worker()
        currentWorker.DoSomeWork()
        Me.pgbStatus.Value += 1
    End Sub

The signature of this method must match the signature of the System.Threading.WaitCallback delegate. In VB syntax, this means the method must be declared as a Sub that takes a single Object parameter called State. Next, you simply call the ThreadPool.QueueUserWorkItem method, passing in the address of the CallDoWork method:

        For currentWorkItem = 1 To 100
            Dim threadQueueCallback As New _
               WaitCallback(AddressOf CallDoWork)
               ThreadPool.QueueUserWorkItem( _
                  threadQueueCallback)
        Next

Note that the ThreadPool class is static, so you don't need to create an instance of it—you can just use it. When this code runs, 100 items will be dropped on the thread pool's work item queue. The CLR will then manage the number of threads in the queue by monitoring the number of items in the queue. On a single CPU machine, there will quickly be 25 threads spawned and added to the system pool, but never more than 25.

Using the system thread pool allows you to control the number of threads your application will spawn. This is important if your application spawns threads in response to things you don't have control over (such as messages arriving on a queue or users calling a Web service). Using the thread pool allows you to guarantee that your application will behave predictably even if the load it is processing increases.

About the Author
Jon Rauschenberger is a partner and the director of technology at Clarity, a Chicago-based information technology consulting firm and Microsoft Solution Provider Partner. Jon is a frequent speaker at conferences and an author for journals. In addition, as a member of Microsoft's Strategic Design Review committee, Jon helps the Microsoft Visual Studio and platform groups formulate their products' future. Contact Jon at jrausch@claritycon.com.