Introduction

Many applications use connection/object pool. A program may require a IMAP connection pool and LDAP connection pool. One could easily implement an IMAP connection pool, then take the existing code and implement a LDAP connection pool. The program grows, and now there is a need for a pool of threads. So just take the IMAP connection pool and convert that to a pool of threads (copy, paste, find, replace????). Need to make some changes to the pool implementation? Not a very easy task, since the code has been duplicated in many places. Re-inventing source code is not an intelligent approach in an object oriented environment which encourages re-usability. It seems to make more sense to implement a pool that can contain any arbitrary type rather than duplicating code. How does one do that? The answer is to use type parameterization, more commonly referred to as templates.

C++ templates allow one to implement a generic Pool<T> template that has a type parameter T. T can be replaced with actual types, for example, class ImapConn, and C++ will generate the class Pool<ImapConn>. Changing the implementation of the Pool becomes relatively simple. Once the changes are implemented in the template Pool<T>, they are immediately reflected in the classes Pool<ImapConn>, Pool<LdapConn>, and Pool<Threads>.

Attached demo project contains:

Docs: Source code documentation.

Source code and project files.

This article demonstrates how to implement generic pool using templates. Code is been compiled on Windows as well as Linux. Please feel free to modify and use.

Below are the requirements to implement generic pool:

Generic: It should be generic enough to work with any type of resources. E.g., Database Connection pool, Thread pool, other resource pool etc...

Pool Size: Size of the pool should be configurable and if required changeable at runtime.

Pool Type: If Pool is fixed size, or temporary connection allowed in case of pool is full.

Object's lifetime: If user doesn't check-in the resource back, what should be the duration at which the object will be considered as expired and returned back to free resources.

Timeout functionality: If Pool is full and temporary connections are not allowed, how long caller function can wait to get object.

The source code contains:

PoolMgr.h which implements the singleton Pool class. It has following functions:

static PoolMgr<T>* GetInstance(): which returns the instance of PoolMgr.

staticvoid DeletePool(): deletes the pool and frees resources.

void Init(unsigned nPoolSize, long nExpirationTime, bool bTempObjAllowed, unsigned nWaitTime): User must initialize the Pool with the following parameters:

PoolSize: Size of the Pool.

ExpirationTime: Duration in seconds. If object is not used for this duration, object would be considered as expired and would be moved to an available object pool.

TempConnAllowd: If Pool is full, should Pool be allowed to create temporary connections.

WaitTime: If temporary connection is not allowed and Pool is full, how long caller function can wait to get the connection from the expired connections.

void ResetPool(): Release all the resources and reset the pool.

T* Checkout(): Check out the resource.

void Checkin(T* pObj): Check in the resource.

template<class T>: Class PoolMgr contains two list of pools. One is for reserved objects and the other for free objects. In a multithreaded environment, it would avoid locking all the objects instead of specific types. E.g., only all free objects or reserved.

ObjectHolder.h: which contains the object pointer and timestamp. It is a template class of type T which allows storing any generic object class.

GenericObject.h: This is a sample generic class which is used for testing this pool. User of this pool needs to either implement following methods in their connection/object class or inherit from GenericObject class.

History

09/16/2004: Added support for thread synchronization.

Please let me know how this article would have been improved and made more useful.

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.

Firstly, thanks.. This was just what i was looking for. In using this framework i have come across two small bugs.

firstly if the pool size is 1 then the function ProcessExpiredObjects() crashes when searching for expired objects.. This is because the erase method returns the iterator to the next object, and then the for loop also increments which moves the iterator on again (in this case past the end!). The new function looks like this:

secondly in the Checkout() function after ProcessExpiredObjects() is called then FindObject() gets called which returns an object you still return NULL instead of the object ref. i have just added the following lines after FindObject()

Hi, I'm attempting to do this mutex unlock as suggested, but I am unclear as to the proper syntax to unlock (before sleeping) and re-lock afterwards. Fairly new to template programming, so I think my confusion is there, but I have tried several syntaxes without success. Thanks!

hi
thanks for this excellent article ! it looks very useful and i'm going to use it !(if u don't mind... )
little question: when i call ResetPool() it causes N destructor calls of ObjectHolder which uses Release method of its T pointer data member.
since this pointer allocated by operator new , i think operator delete should be used (or i missed something). how the memory of m_pObj freed ?
i'm a new programmer and i'll glad to recieve some explanations.

In the class "PoolMgr", you have the function "Init()" defined twice, and in the class "GenericObject", you have the statement, "return true;" appearing outside the function, "MakeUsable".

While your article does have merit, there are some things you "squeaked" by without the benefit of further explanation (e.g. When is the Singleton object, "PoolMgr" going to destroy itself, since this is the surest way to avoid 'resource leaks'? [See Alexandrescu "Modern C++ Design" page 133, fourth paragraph.] Instead, you made your point by showing "manual" deletion of the resources to support resetting of the pool. Even so, you did not use an automatic deletion mechanism to take care of resource deletion. You used "time out" as a sort of signal for deletion, followed by the manual method of doing it.)

There is nothing wrong with how you wrote your article, it's a first step is how I would consider it. An excellent "first step" nonetheless.

I haven't read your follow-up article as yet, but I will, and I shall be looking to see how you handle some of the other points that would describe a more comprehensive manner in dealing overall with Policy-Based Designs.

In the class "PoolMgr", you have the function "Init()" defined twice, and in the class "GenericObject", you have the statement, "return true;" appearing outside the function, "MakeUsable".

>>>> If you down load the code, it don’t have the Init() function as well as “return true” outside the function. I had also noticed this but before I update the article, it wasv moved out from “unedited Reader Contributions” section. So I could not modify it.

While your article does have merit, there are some things you "squeaked" by without the benefit of further explanation (e.g. When is the Singleton object, "PoolMgr" going to destroy itself, since this is the surest way to avoid 'resource leaks'? [See Alexandrescu "Modern C++ Design" page 133, fourth paragraph.] Instead, you made your point by showing "manual" deletion of the resources to support resetting of the pool. Even so, you did not use an automatice deletion mechanism to take care of resource deletion. You used "time out" as a sort of signal for deletion, followed by the manual method of doing it.)

>>>> I agree with your point. But when I wrote the article, I concentrated more on Pool functionality in generic way rather than singleton pattern. The main aim of this article is to show the reusable pool design with the power of templates.

There is nothing wrong with how you wrote your article, it's a first step is how I would consider it. An excellent "first step" nonetheless.

I haven't read your follow-up article as yet, but I will, and I shall be looking to see how you handle some of the other points that would describe a more comprehensive manner in dealing overall with Policy-Based Designs.

>>>> Here is the link for my new article :http://www.codeproject.com/useritems/Generic_Pool_Design.asp
Here, again I have concentrated more on policy based design to achieve different requirements about the pool rather than singleton pattern. I have used Loki::SingletonHolder<> to create singleton instance of the class instead of reinventing the wheel.

if you could come up with a VC 6 version for those members who are still using VC 6.

Because I am one of them who still uses that version, I only have your code from which to follow what your wonderful sample achieves, without the added benefit of seeing it work (which limits my ability to conduct any kind of experimenting with it).

Nevertheless, it's a VERY GOOD!! article and not only am I voting a '5' for it, but am looking forward to the next one you propose writing.

If you create new project in VC6 and add all these header and CPP files, it should compile and work fine because I developed this application on Linux with GCC. Only you might need to look at the Sleep() function if it is different in VC6 verse VC7. I don't see any reason if microsoft has changed that. Look for below code in PoolMgr.h

I have submitted my article "Generic Pool :policy based design"
http://www.codeproject.com/useritems/Generic_Pool_Design.asp
I am sorry, I could not provide the demo version for VC6 as I don't have IDE avaiable.

I have plan to provide support for Multithreading as well as sweeper thread which will cleanup the expired resources. In my next article, Generic Pool using Policy based design, I will have this support. thanks for your comment.

There is no need to write a 'sweep up' implementation to tidy up based on some regular time or indeed by running the PoolMgr in a separate thread; just tidy up each time a request is made for a pool entry. Of course, if you are worried about freeing resources used by a pool entry then a sweeper would be useful, but would require a link between the PoolMgr and the stored objects. If this kind of integration is available then you could also provide notification to the pooled objects of when they have been locked/released/forcibly released.

This could have been a very interesting article, but now it's just a zip file with code... It would have been nice if you would have described the design tradeoffs you made and the interface of the Pool template, along with a simple example maybe. Eg is it possible to change the pool size at runtime? If no, why did do choose this design? Etc...