Search Forum
(57415 Postings)
Search Site/Articles

Archived Articles
712 Articles

C# Books
C# Consultants
What Is C#?
Download Compiler
Code Archive
Archived Articles
Advertise
Contribute
C# Jobs
Beginners Tutorial
C# Contractors
C# Consulting
Links
C# Manual
Contact Us
Legal

GoDiagram for .NET from Northwoods Software www.nwoods.com


              
Printable Version

Object Pooling with Managed Code
By Scott Sherer

Summary

With the advent of the .NET platform, writing code that pools objects and threads has become a simple task. By using the Threading and Collections namespaces, you can create robust object pooling applications. This could also be done by implementing COM+ interop interfaces into your code. If you don't have any reservations about the additional overhead of marshalling as well as the tight coupling of your code to COM+, then use COM+ interop. On the other hand, if you are looking for advanced control and better overall performance, then you can write your own object pools.

Download objectpooling_code.zip

Writing your own object pools has the following benefits:

· Custom performance counters - Custom performance counters can be easily implemented into your code. Although COM+ offers several performance counters, I have often found the need to have additional performance counters related to how my objects are being pooled.
· Custom tracing and event logging - Objects can use the Trace.Write(If) methods to log events and errors. This leaves where and how an event is logged up to the hosting application. This approach also allows for centralized handling of events and errors.
· Custom messaging - You can create customized messaging schemes that replace LCE (Loosely Coupled Events) thus improving the overall performance of your application.
· No interop marshalling - Because all your object pooling code is written in the managed environment, your code will run marginally faster (given that you write your code efficiently). The caveats to creating your own object pools are:
· More coding. Using COM+ is as simple as adding an attribute.
· Code is more complex, thus requiring more programmers with advanced skills. In my projects, I have used both COM+ and custom object pooling depending on the timeframes and requirements of the projects.

Defining the Namespaces

The namespaces used for the project are as follows:

 namespace Sample.ObjectPooling{
  using System;
  using System.Collections;
  using System.Reflection;
  using System.Threading;
Creating the Object Context Class

The object context class will be responsible for managing the lifetime of the pooled object. This object could also contain addition information about the object.

public class ObjectContext{
    internal Stack m_oStack;
    private int m_iTimeout;
    public bool TimedOut = false;
    public object Object;
    public ObjectContext(Stack Stack, int Timeout){
      this.m_iTimeout = Timeout;
      this.m_oStack = Stack;
    }
    private Timer IdleTimer = null;
    private void IdleTimeoutCallback(object State){this.StopIdleTimer(); this.TimedOut = true;}    
    public bool TimedOut = false;
    internal void StopIdleTimer(){this.IdleTimer.Dispose();}
    public void Dispose(){
      this.StopIdleTimer();
      this.TimedOut = true;
      this.m_oStack = null;
      this.Object = null;
    }
    public void Pool(){
      this.IdleTimer = new Timer(new TimerCallback(this.IdleTimeoutCallback),null,m_iTimeout,0);
      this.m_oStack.Push(this);
    }
  }
This class contains a constructor into which the parent passes a reference to its containing stack (the object pool) and the idle timeout period (in milliseconds). When an object is pulled from the stack, the StopIdleTimer method is called by the parent to ensure that the object doesn't timeout inaccurately. When the user of the object is done, it calls on the object context's Pool method which adds the object back to the pool (i.e. pushes an object reference onto the stack).

If at any point, the internal idle-timeout timer elapses, the object context disposes of all external references and sets its TimedOut field to true. This field is used by the parent class to know which objects can be cleaned up (i.e. removed from the stack).

Creating the Object Pooling Class

The next step is to create the ObjectPooling class. This class uses a Collections.Stack object along with the ObjectContext class to create and manage its object pool.

public class ObjectPool{
    private Type m_oType;
    private int m_iTimeout = 60000;
    internal Stack m_oPool = new Stack();
    public ObjectPool(System.Type Type){
      this.m_oType = Type;
    }
    public ObjectPool(System.Type Type, int Timeout){
      this.m_oType = Type;
      this.m_iTimeout = Timeout;
    }
    public Type Type{get{return m_oType;}}
    public ObjectContext GetObjectContext(){return this.GetObjectContext(null);}
    public ObjectContext GetObjectContext(object[] Args){
      ObjectContext oObject = null;
      while(m_oPool.Count!=0){
        oObject = (ObjectContext)m_oPool.Pop();
        if(!(oObject.TimedOut)){
          oObject.StopIdleTimer();
          break;
        }
        else{oObject=null;}
      }
      if(oObject==null){
        oObject = new ObjectContext(m_oPool, m_iTimeout);
        oObject.Object = Activator.CreateInstance(m_oType, Args);
      }
      return oObject;
    }
    public void Dispose(){
      while(m_oPool.Count!=0){
        ObjectContext oItem = (ObjectContext)m_oPool.Pop();
        oItem.Dispose();
      }
    }
  }
}
When creating the object pool, the type of object stored in the pool along with the idle timeout is specified. The most significant method of this class is GetObjectContext. This method looks for an existing object (and its context) in the pool. If no object can be found in the pool, a new object (and context) is created. If the object was obtained from the stack, the StopIdleTimer method is called on the object's context to ensure that it doesn't time-out.

The Dispose method is used to clean-up any object that are in the queue. This method should always be called when the object pool is no longer needed (normally at application shutdown).

Using the Object Pool

The following code is an example of using the object pool classes above to create one or more worker objects. Each worker object pops up a message box that contains its hash code. By pressing the enter key in the console at different intervals, you can see how some objects will timeout and others will be reused. The default timeout used for this sample is 1 minute.

namespace WindowsApplication2{
  using System;
  using System.WinForms;
  using Sample.ObjectPooling;
  using System.Threading;
  public class Test{
    private static void Main(){
      ObjectPool oPool = new ObjectPool(typeof(WindowsApplication2.Worker));
      while(Console.ReadLine() != "x"){
        ObjectContext oContext = oPool.GetObjectContext();
        ThreadPool.QueueUserWorkItem(new WaitCallback(new Test().ThreadProc), oContext);
      }
      oPool.Dispose();
    }
    public void ThreadProc(object State){
      ObjectContext oContext = (ObjectContext)State;
      ((Worker)oContext.Object).ShowHashCode();
      oContext.Pool();
    }
  }
  public class Worker{
    public void ShowHashCode(){
      MessageBox.Show(this.GetHashCode().ToString());
    }
  }
}
Conclusion

As you can see, creating an object pool has become a trivial task using the .NET framework. One improvement on the above code would be to add performance counters along with remoting capabilities to your object pool.

About The Author

Scott Sherer is a Systems Architect based out of Phoenix, Arizona. He started programming at the age of 10 and has loved programming with a passion ever since. His experiences have included Document Imaging, Building Automation Systems, and Banking. He has been using C# and the .NET framework since December, 2000, and is currently on contract with the City of Phoenix where he is assisting in the conversion of existing software to the new .NET platform. You can reach him at scotts@dakinisoft.com.