65.9K
CodeProject 正在变化。 阅读更多。
Home

基于模板的通用池(使用 C++)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.29/5 (21投票s)

2004年8月27日

4分钟阅读

viewsIcon

124720

downloadIcon

1531

基于模板的通用 C++ 对象池。

引言

许多应用程序都使用连接/对象池。一个程序可能需要一个 IMAP 连接池和一个 LDAP 连接池。可以轻松地实现一个 IMAP 连接池,然后复制现有代码来实现一个 LDAP 连接池。程序不断增长,现在需要一个线程池。于是就复制 IMAP 连接池的代码,并将其转换为线程池(复制、粘贴、查找、替换???)。需要对池实现进行一些更改?这并不容易,因为代码已经在多个地方被复制。在鼓励可重用性的面向对象环境中,重复编写源代码并不是一种明智的方法。实现一个可以容纳任何任意类型的池,而不是复制代码,似乎更有意义。如何做到这一点?答案是使用类型参数化,更常称为模板。

C++ 模板允许实现一个具有类型参数 T 的通用 Pool<T> 模板。T 可以被替换为实际类型,例如,类 ImapConn,C++ 会生成类 Pool<ImapConn>。更改池的实现将变得相对简单。一旦在模板 Pool<T> 中实现了更改,这些更改将立即反映在类 Pool<ImapConn>Pool<LdapConn>Pool<Threads> 中。

附带的演示项目包含

  1. 文档:源代码文档。
  2. 源代码和项目文件。

本文演示了如何使用模板实现通用对象池。代码已在 Windows 和 Linux 上编译。请随时修改和使用。

以下是实现通用对象池的要求

  • 通用性:它应该足够通用,能够与任何类型的资源一起工作。例如,数据库连接池、线程池、其他资源池等...
  • 池大小:池的大小应该是可配置的,并且如果需要,可以在运行时更改。
  • 池类型:如果池是固定大小的,或者在池已满的情况下允许临时连接。
  • 对象的生命周期:如果用户不将资源交还,对象将在多长时间后被视为已过期并返回到空闲资源池。
  • 超时功能:如果池已满且不允许临时连接,调用函数可以等待多久才能获取对象。

源代码包含

  1. PoolMgr.h:实现了单例 Pool 类。它具有以下函数
    template<class T> 
    class PoolMgr
    {
        typedef ObjectHolder<T> ObjHolder;  
        typedef list<ObjHolder> ObjList;  
        static Mutex m_mPool; // Mutex for Pool static instance
       Mutex m_mData; // Mutex for Pool data
    
    public:
        // Get the Instance of pool manager
        static PoolMgr<T>* GetInstance()
        {
            if(!m_pPoolMgr) {
               Lock<Mutex> gaurd(m_mPool);
               if(!m_pPoolMgr)
                   m_pPoolMgr = new PoolMgr<T>()
           }
           return m_pPoolMgr;
     
        }
       // delete the pool
       static void DeletePool()
       {
           if(m_pPoolMgr) {
               Lock<Mutex> gaurd(m_mPool);
                if(m_pPoolMgr){
                    delete m_pPoolMgr;
              m_pPoolMgr = NULL;
          }
       }
    
        // Initliaze pool
        void Init(unsigned nPoolSize, long nExpirationTime, 
                  bool bTempObjAllowed, unsigned nWaitTime = 3)
        {
           …
        }
         // Reset the pool
        void ResetPool()
        {
            .....
        }
         // Initliaze pool
        void Init(unsigned nPoolSize, long nExpirationTime, 
                  bool bTempObjAllowed, unsigned nWaitTime = 3)
        {
           ...
        }
        
         // Checkout the Object from pool  
        T* Checkout()
        {
         ...        
        }
        // checkin the Object into pool                          
        void Checkin(T *pObj)
        {
         ...
        }
    private:
        
        static PoolMgr<T> *m_pPoolMgr; // static instance of PoolMgr
     
        //private constructor
         PoolMgr()
        {
            m_nPoolSize = 0;
            m_nExpirationTime = 600; // in sec
            m_bTempObjAllowed = true;
            m_nWaitTime = 3;
        }
        // distructor   
        ~PoolMgr()
        {
           
        }
        // pool size : default 0
        unsigned m_nPoolSize;
        // wait time: How long calling function can wait to find object
        unsigned m_nWaitTime;
        // Object expiration time: default 600
        long m_nExpirationTime;
        // if pool is full, is tempobject allowed
        bool m_bTempObjAllowed;
        // reserved objects
        ObjList m_oReserved;
        // free objects
        ObjList m_oFree;
               
    };
    template<class T> PoolMgr<T>* PoolMgr<T>::m_pPoolMgr = NULL;
    //initialize static instance
    template<class T> Mutex PoolMgr<T>::m_mPool;
    • static PoolMgr<T>* GetInstance():返回 PoolMgr 的实例。
    • static void DeletePool():删除池并释放资源。
    • void Init(unsigned nPoolSize, long nExpirationTime, bool bTempObjAllowed, unsigned nWaitTime):用户必须使用以下参数初始化池
      • PoolSize:池的大小。
      • ExpirationTime:持续时间(秒)。如果对象在此持续时间内未使用,则该对象将被视为已过期,并将移至可用对象池。
      • TempConnAllowd:如果池已满,是否允许池创建临时连接。
      • WaitTime:如果不允许临时连接且池已满,调用函数可以等待多久才能从已过期连接中获取连接。
    • void ResetPool():释放所有资源并重置池。
    • T* Checkout():签出资源。
    • void Checkin(T* pObj):签入资源。
    • template<class T>PoolMgr 类包含两个池列表。一个用于已保留对象,另一个用于空闲对象。在多线程环境中,这可以避免锁定所有对象,而是锁定特定类型的对象。例如,只锁定所有空闲对象或已保留对象。
  2. ObjectHolder.h:包含对象指针和时间戳。它是一个类型为 T 的模板类,允许存储任何通用对象类。
    template<class T>
    class ObjectHolder
    {
        public:
              // constructor
            ObjectHolder()
            {
               m_nTimeStamp = -1;
                m_pObj = NULL;
            }
     
           // distructor
            ~ObjectHolder()
            {
                if(m_pObj) {
                    m_pObj->Release();
                  m_pObj = NULL;
                }
                
            }
     
           //Initliaze object
            void InitObject()
            {
              if(!m_pObj) {
                   m_pObj = new T();
                   m_pObj->Init();
              }
            }
                            
                        
        private:
            T *m_pObj;  // object pointer
            long  m_nTimeStamp;  // timestamp
            
    };
  3. GenericObject.h:这是一个用于测试此池的示例通用类。此池的用户需要在其连接/对象类中实现以下方法,或继承自 GenericObject 类。
    class GenericObject
    {
        public:
              //constructor
              GenericObject() {}
              //destrctor
              ~GenericObject() {}
              
              //Initliaze object
              virtual void Init() {}
              
               
              //Release the resource related to object
              virtual void Release() {}
              
              // Check if object is still usable
              virtual bool IsUsable()
              {
                return true;
              }
                
              // If object is not usable, make it usable
              virtual bool MakeUsable()
              {
                  if(!IsUsable()) {
                      Init();
                  return true;
              }
               
    };

    这里

    1. void Init():初始化对象。如果对象需要建立连接,请在此函数中执行。
    2. void Release():释放资源。
    3. bool IsUsabled():此对象是否仍然可用?
    4. bool MakeUsable():如果它不可用,尝试使其可用,如果成功,则返回 true。如果成功使其可重用,这将避免构造新对象。
  4. MutexWin.h(Windows)和 Mutex.h(Linux)
    // Lock class
    template <class T > class Lock 
    {
     T& obj_; // type object
    public:
    // Lock
     Lock(T& obj):obj_(obj)
     {
      obj_.Lock();
     }
    // Unlock
    ~Lock()
    {
      obj_.Unlock();
    }
    };
    // Mutex class 
    class Mutex
    {
     public:
     // constructor
     Mutex()
     {
       InitializeCriticalSection(&m_mMutex);
      }
      // destructor
      virtual ~Mutex()
      {
       DeleteCriticalSection(&m_mMutex);
      }  
    // lock
    bool Lock()
    {
      EnterCriticalSection(&m_mMutex);
      return true;
    }
    // unlock
    bool Unlock()
    {
      LeaveCriticalSection(&m_mMutex);
      return true;
    }
    private:
      CRITICAL_SECTION m_mMutex; // critical section as mutex
      void operator=(Mutex &m_mMutex) {} // private = operator
      Mutex( const Mutex &m_mMutex ) {} // private copy constructor
    };
  5. main.c:这是一个示例 main 函数,它获取 PoolMgr 的实例,并签出和签入 GenericObject
    PoolMgr<GenericObject> *pMgr = PoolMgr<GenericObject>::GetInstance();
    if(pMgr)
    {  
        // Pool size 10, object expiration time 600 sec
        // and temporary connection not allowed
        pMgr->Init(10,600, false);
        GenericObject *pObj = NULL;
        pObj = pMgr->Checkout();
        pMgr->Checkin(pObj);
        pMgr->ResetPool();
        
       // ExpirationTime test: Pool size is 1, expiration time
       // is 10 secs, and temporary connections not allowed.
       // Here when you checkout 2nd object, it would wait for 10 seconds
       // and the 1st object would be garbage collected
       // and moved to free resource.
        pMgr->Init(1,10, false);
        GenericObject *pObj = NULL;
        pObj = pMgr->Checkout();
        std::cout << "1st Object checked out " << std::endl;
        pObj = pMgr->Checkout();
        std::cout << "2st Object checked out after 10 secs " << std::endl;
    
        pMgr->ResetPool();
    }
    PoolMgr<GenericObject>::DeletePool(); // delete and free all resources

请参阅我的另一篇关于对象池设计的文章:通用对象池:基于策略的设计

历史

  • 2004/09/16:添加了对线程同步的支持。

请告诉我如何改进这篇文章,使其更有用。

© . All rights reserved.