Understanding Object Pooling in Microsoft .NET
page 6 of 8
by Joydip Kanjilal
Feedback
Average Rating: 
Views (Total / Last 10 Days): 46881/ 69

Implementing an Object Pool in C#

We would design an object pool based on some predefined goals/objectives. These are stated as under the following.

·         Ease of use and reusable

·         Thread Safe

·         Type Safe

·         Scalable

·         Configurable

These are the basic objectives that the pool should adhere to. With these in mind, we will now implement a simple Object Pool in C# and use this pool for creation, usage and destruction of objects.

The Pool Manager Class

The following code example illustrates how an object pool can be created. I have provided enough comments to enable the reader to understand how the Pool Manager class works. This class is based on the Singleton Pattern, i.e., there can be at any point of time only one instance of this class.

Listing 1

using System;
using System.ComponentModel; 
using System.Collections; 
using System.Threading; 
 
namespace ObjectPooling
{
      /// <summary>
      /// A class to manage objects in a pool. 
///The class is sealed to prevent further inheritence
      /// and is based on the Singleton Design.
      /// </summary>
      public sealed class PoolManager
      {
            private Queue poolQueue = new Queue();
            private Hashtable objPool = new Hashtable();
            private static readonly object objLock = new object();
            private const int POOL_SIZE = 10;
            private int objCount = 0;
            private static PoolManager poolInstance = null;
 
            /// <summary>
            /// Private constructor to prevent instantiation
            /// </summary>
            private PoolManager()
            {
 
            }
 
            /// <summary>
            /// Static constructor that gets 
///called only once during the application's lifetime.
            /// </summary>
            static PoolManager()
            {
                  poolInstance = new PoolManager();
            }
 
            /// <summary>
            /// Static property to retrieve the instance of the Pool Manager
            /// </summary>
 
            public static PoolManager Instance 
            {
                  get
                  {
                        if(poolInstance != null) 
                        {
                              return poolInstance;
                        }
 
                        return null;
                  }
            }
 
            /// <summary>
            /// Creates objects and adds them in the pool
            /// </summary>
            /// <param name="obj">The object type</param>
            public void CreateObjects(object obj)
            {
                  object _obj = obj;
                  objCount = 0;
                  poolQueue.Clear();
                  objPool.Clear();
 
                  for(int objCtr = 0; objCtr < POOL_SIZE ; objCtr ++)
                  {
                        _obj = new object();
 
                        lock(objLock)
                        {
                              objPool.Add(_obj.GetHashCode(),_obj);
                              poolQueue.Enqueue(_obj);
                              objCount ++;                              
                        }
                  }
            }
 
            /// <summary>
            /// Adds an object to the pool
            /// </summary>
            /// <param name="obj">Object to be added</param>
            /// <returns>True if success, false otherwise</returns>
            public bool AddObject(object obj)
            {
                  if(objCount == POOL_SIZE)
                        return false;
 
                  lock(objLock)
                  {
                        objPool.Add(obj.GetHashCode(),obj);
                        poolQueue.Enqueue(obj);
                        objCount ++;
                  }
 
                  return true;
            }
 
            /// <summary>
            /// Releases an object from the pool at the end of the queue
            /// </summary>
            /// <returns>The object if success, null otherwise</returns>
            
            public object ReleaseObject()
            {
                  if(objCount == 0)
                        return null;
 
                  lock(objLock)
                  {
                        objPool.Remove(poolQueue.Dequeue().GetHashCode());
                        objCount --;
                        if(poolQueue.Count > 0)
                              return poolQueue.Dequeue();                     
                  }
 
                  return null;
            }
 
            /// <summary>
            /// Releases an object from the pool
            /// </summary>
            /// <param name="obj">Object to remove from the pool</param>
            /// <returns>The object if success, null otherwise</returns>
            public object ReleaseObject(object obj)
            {
                  if(objCount == 0)
                        return null;
 
                  lock(objLock)
                  {
                        objPool.Remove(obj.GetHashCode());
                        objCount --;
                        RePopulate();
                        return obj;
                  }
            }
 
            /// <summary>
            /// Method that repopulates the 
///Queue after an object has been removed from the pool.
            /// This is done to make the queue 
///objects in sync with the objects in the hash table.
            /// </summary>
            private void RePopulate()
            {
                  if(poolQueue.Count > 0)
                        poolQueue.Clear();
 
                  foreach (int key in objPool.Keys)
                  {
                        poolQueue.Enqueue(objPool[key]);
                  }
            }
 
            /// <summary>
            /// Property that represents the current no of objects in the pool
            /// </summary>
            public int CurrentObjectsInPool
            {
                  get
                  {
                        return objCount;
                  }
            }
 
            /// <summary>
            /// Property that represents the maximum no of objects in the pool
            /// </summary>
            public int MaxObjectsInPool
            {
                  get
                  {
                        return POOL_SIZE;
                  }
            }
      }
}

Using the Pool Manager Class

The following code snippets in Listings 2, 3 and 4 show how we can use the PoolManager created in Listing 1.

Listing 2

object obj1 = new object();
object obj2 = new object();
PoolManager poolManager = PoolManager.Instance;
poolManager.AddObject(obj1);
poolManager.AddObject(obj2);
MessageBox.Show(poolManager.CurrentObjectsInPool.ToString());
poolManager.ReleaseObject(obj1);
MessageBox.Show(poolManager.CurrentObjectsInPool.ToString());
object obj = null;
for(;;)
{
      obj = poolManager.ReleaseObject();
      if(obj != null)
            MessageBox.Show(obj.GetHashCode().ToString());
      else
      {
            MessageBox.Show("No more objects in the pool");
            break;
      }
}

Listing 3

PoolManager poolManager = PoolManager.Instance;
object obj1 = new object();
object obj2 = new object();
object obj3 = new object();
poolManager.AddObject(obj1);
poolManager.AddObject(obj2);
 
MessageBox.Show(poolManager.CurrentObjectsInPool.ToString());
object obj = poolManager.ReleaseObject();
MessageBox.Show(poolManager.CurrentObjectsInPool.ToString());
if(obj.GetHashCode() == obj1.GetHashCode())
      MessageBox.Show("Object 1 has been released from the pool");
else if(obj.GetHashCode() == obj2.GetHashCode())
      MessageBox.Show("Object 2 has been released from the pool");

Listing 4

PoolManager poolManager = PoolManager.Instance;
ArrayList arr = new ArrayList();
poolManager.CreateObjects(arr);
object obj = poolManager.ReleaseObject();
MessageBox.Show("No of objects in Pool is: "+
poolManager.CurrentObjectsInPool.ToString(),
"The hash code of the released object is: "+
obj.GetHashCode().ToString());
obj = poolManager.ReleaseObject();
MessageBox.Show("No of objects in Pool is: "+
poolManager.CurrentObjectsInPool.ToString(),
"The hash code of the released object is: "+
obj.GetHashCode().ToString());

Note how we have used the PoolManager in the code listings above. The CreateObjects method has been used in Listing IV to create a specified number of objects of the ArrayList type and store them in the pool. However, the major drawback of this design is that there would be enough boxing and un-boxing overhead involved on storing and retrieving the objects to and fro from the pool. To eliminate this, I would recommend the usage of Generics. Further, the size of the pool (the maximum number of objects that the pool can contain) is also fixed and is not configurable. I leave it to the readers to make the necessary changes to the Pool Manager class to suit their needs.


View Entire Article

User Comments

No comments posted yet.






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-03-28 2:51:29 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search