5,427,303 members and growing! (18,225 online)
Email Password   helpLost your password?
General Programming » Threads, Processes & IPC » Thread Pooling     Intermediate

Thread variables and the .NET thread pool

By Xiangyang Liu 刘向阳

Optimize your code in multithreaded .NET applications
C++/CLI, C#, VB.NET 1.0, .NET 1.1, Win2K, WinXP, Win2003, Windows, .NET, ASP.NET, Visual Studio, Dev

Posted: 10 Jul 2003
Updated: 10 Jul 2003
Views: 50,819
Bookmarked: 15 times
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
29 votes for this Article.
Popularity: 6.35 Rating: 4.34 out of 5
3 votes, 10.3%
1
2 votes, 6.9%
2
2 votes, 6.9%
3
0 votes, 0.0%
4
22 votes, 75.9%
5

Overview of the problem

ASP.NET web applications (including web services) use threads in a thread pool to process client requests. These threads are created by the .NET framework, they will be reused to process multiple requests. The number of threads in the pool will increase only when the number of simultaneous client requests increases. Typically, you have no control over which thread would be used to process a particular incoming request, your application could have processed thousands of requests from the users, but only one thread did all the work. The other extreme situation is that many requests came in at exactly the same moment so multiple threads have to be used to do the work.

Suppose a method in one of your classes is to be executed by threads in the thread pool, a good example is the page_load method of your aspx page class. How do you declare and use an object that is only visible to the current thread? For example, you may want to use an old COM object in this method. This COM object requires some heavy processing at the time of creation and initialization. For performance reasons, you probably don't want to create and initialize this COM object each time your method is called.

If you declared the object as a global (static or shared) variable, then all concurrently running threads would be able to access it. Declaring the object as a non-static class variable may not help because, for example, each time a new request reaches your web application, a new instance of your aspx page class will be used to process the request (even if the same thread in the thread pool is doing the work), therefore you will have to create and initialize your COM object for each user request.

There is nothing wrong with sharing an object between different threads if the object is thread-safe or you have added synchronization code so that only one thread can access it at a time (all the other threads will block until the owner thread releases the object). However, if your object is working on a lengthy database transaction, it may not be the best approach to require all the other threads to wait until the operation is completed.

In my recent article Using COM objects in multithreaded .NET applications, I presented a solution for this problem. Basically, I provide a utility class that helps you to create (and store) a COM object in the current thread and retrieve it at a later time. This is ideal for .NET applications that use a thread pool like ASP.NET. What I want to do in this article is generalize the idea to any object (it is not restricted to COM object any more).

The solution

My ObjMan class is contained in the ThreadObjectManager.dll. It is modified from the code in my other article mentioned above. This class has three static (shared) methods, GetObject, SaveObject, and RemoveObject. Here is a description of these methods.

  • GetObject: It takes three parameters, the return type is Object. The first parameter is the name string of the object to be returned. This name string is supplied by the user to differentiate between different objects created within the same thread. The second and the third parameters are optional, they are the class name string and the assembly name string. When this method is called, it will retrieve the object with given name, if it is already created (or saved) within the same thread by a previous call to GetObject (or a call to SaveObject). If no such object can be found and no other parameters are specified, the method will return null (Nothing ). If the class name and the assembly name parameters are specified, the method will use the parameters to load the corresponding assembly and to create an instance of the corresponding class, the newly created object will be saved with the given name string. The object with given name, if found or created, will be returned.
  • SaveObject: This method has two parameters and the return type is bool (Boolean). The first parameter is the name string of the object to be saved. The second parameter is the object itself. If you create an object and call the SaveObject method, passing a name string you choose and the object value, it will save your object for the current thread so that you can retrieve it later by calling the GetObject method from the same thread using the name string. Unlike GetObject, the SaveObject method does not create the object for you, you have to create the object yourself before calling SaveObject.
  • RemoveObject: This method simply removes the object with given name from the current thread. It is not possible to remove an object created (or saved) from a different thread.

Please note that a method call such as GetObject("MyObjName") returns different objects if executed from different threads, the object name string only differentiates objects created (or saved) within the same thread.

Here is a sample C# code of using the GetObject method to create the COM object described in my other article. You need to register the DummyCom.dll and add it to your .NET project so that the .NET wrapper DLL will be generated.

using DUMMYCOMLib;
using ThreadObjectManager;
...
Object obj = ObjMan.GetObject("MyDummyObj", 
             "DUMMYCOMLib.DummyObjClass", "Interop.DUMMYCOMLib");
String sOutput = ((DummyObjClass)obj).Test("This is a test");
// ObjMan.RemoveObject("MyDummyObj");

...

When the above code is executed, the COM object will be created only once in each thread, unless you uncomment the line that calls RemoveObject. For .NET internal objects, it is easier to combine the SaveObject and the GetObject methods as follows, since there is no need to load any assembly.

using ThreadObjectManager;
...
Object obj = GetObject("MyHashtable");
if(obj== null)
{
    obj = new Hashtable();
    ObjMan.SaveObject("MyHashtable", obj);
    ((Hashtable)obj).Add("MyString", 
        "This string is added at most once for each thread");
}
String sObjName = Guid.NewGuid().ToString();
Hashtable myHashtable = (Hashtable)obj;
myHashtable.Add(sObjName, "This string is added every time");
...

Again, the myHashtable object will be created and saved only once for each thread that executes the above code.

The implementation

The implementation of the ObjMan class is simple and straightforward. Internally, the ObjMan class uses a global (static) HashTable to store data. Data items in this hashtable are hashtables themselves. Each of these child hashtables corresponds to a thread, the key for the parent hashtable is the thread name. Each thread accesses its own hashtable using the thread name. If a thread has no name, a dynamically generated GUID string will be assigned as its name.

When an object is created and saved, it is actually stored in the child hashtable of the current thread. The object name string will be the key for the child hashtable. When an object is retrieved, the code will first find the child hashtable for the current thread, then use the given object name string to find the item stored in the child hashtable.

Thank you for reading my article. Please visit my home page for my other articles and tools.

Latest updates

  • July 14, 2003. Modified article text.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Xiangyang Liu 刘向阳



Location: United States United States

Other popular Threads, Processes & IPC articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 5 of 5 (Total in Forum: 5) (Refresh)FirstPrevNext
Subject  Author Date 
Generaleeesussvinoth811:26 30 Sep '05  
GeneralSerious limitations with this approachmembercklein20:22 11 Jul '03  
GeneralRe: Serious limitations with this approachmemberXiangyang Liu2:31 12 Jul '03  
GeneralRe: Serious limitations with this approachmembercklein8:44 12 Jul '03  
GeneralRe: Serious limitations with this approachmemberXiangyang Liu21:21 12 Jul '03  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 10 Jul 2003
Editor: Smitha Vijayan
Copyright 2003 by Xiangyang Liu 刘向阳
Everything else Copyright © CodeProject, 1999-2008
Web09 | Advertise on the Code Project