views:

316

answers:

4

I have a class that is expensive to construct, in terms of time and memory. I'd like to maintain a pool of these things and dispense them out on demand to multiple threads in the same process.

Is there a general-purpose object pool that is already tested and proven? (I don't want COM+ pooling.)

A: 

Why not just write a singleton that just serves as the gateway to the array of objects that has been created.

When an object is handed out, then remove it from the available list, put it in the checked out list, and then when it is returned, reverse that.

By using a singleton for this you have a static class for everything to call, and if the expensive class is an inner class of the singleton, then nothing else can create the expensive class, and you can control how many objects to create, easily.

James Black
Well ya, that would work. an object pool can be pretty simple. But then there are additional niceties like, a bounded object population (no lower than x, no higher than y), named objects, object properties, that kinda thing. I just wondered if someone had designed it already and considered these things.
Cheeso
@Cheeso - you may want to add that to your question, as it will change the question quite a bit.
James Black
+4  A: 

Pulled straight from MSDN, here's an example of using one of the new concurrent collection types in .NET 4:

The following example demonstrates how to implement an object pool with a System.Collections.Concurrent.ConcurrentBag<T> as its backing store.

public class ObjectPool<T>
{
    private ConcurrentBag<T> _objects;
    private Func<T> _objectGenerator;

    public ObjectPool(Func<T> objectGenerator)
    {
        if (objectGenerator == null)
            throw new ArgumentNullException("objectGenerator");
        _objects = new ConcurrentBag<T>();
        _objectGenerator = objectGenerator;
    }

    public T GetObject()
    {
        T item;
        if (_objects.TryTake(out item))
            return item;
        return _objectGenerator();
    }

    public void PutObject(T item)
    {
        _objects.Add(item);
    }
}
280Z28
Thank you, I saw this one. It depends on .NET 4.0. Unfortunately, I am depending on NET 2.0. !!!
Cheeso
+3  A: 

No Cheeso, there is no general object pool like this. But it is a good idea. I think this would be pretty simple to develop. The key thing is making it work well in a threaded environment.

I think this is an interesting design problem. For example, if this needs to to scale on sever class hardware -and- you will give objects to indivudual threads often then you might do this:

  1. Keep a single central pool of objects.
  2. Keep a per-thread pool (a cache) that is populated when its called for the first time for a thread, and when it becomes empty.

This way, you avoid per-thread contention for most requests.

Different operational conditions would lead you to a different design. For example, if object allocations are rare or the number of threads is low, then it might be simpler just to have a lock around a collection. This won't scale well, but in this case, it would need to.

If you design the class or interface correctly, then you could change the implementation over time to handle more complex scenarios.

Foredecker
+1  A: 

The ObjectPool class proposed by 280Z28 looks pretty good. You might also consider creating another class that implements IDisposable and wraps the return value of GetObject(). This will ensure objects are returned to your pool and reads nicely:

class ObjectPoolReference<T> : IDisposable
{
 public ObjectPool<T> Pool { get; private set; }

 public T Instance { get; private set; }

 public ObjectPoolReference(ObjectPool<T> pool, T instance)
 {
  Pool = pool;
  Instance = instance;
 }

 ~ObjectPoolReference()
 {
  Dispose();
 }

 #region IDisposable Members

 private bool _Disposed = false;

 public void Dispose()
 {
  if (!_Disposed)
  {
   Pool.PutObject(Instance);

   _Disposed = true;
  }
 }

 #endregion
}

//instance of the pool
ObjectPool<Foo> Pool;

//"using" ensures the reference is disposed at the end of the block, releasing the object back to the pool
using (var Ref = Pool.GetObject())
{
    Ref.Instance.DoSomething();
}
Michael Petito