#ifndef HV_OBJECT_POOL_H_ #define HV_OBJECT_POOL_H_ /* * @usage unittest/objectpool_test.cpp */ #include #include #include #include #define DEFAULT_OBJECT_POOL_INIT_NUM 0 #define DEFAULT_OBJECT_POOL_MAX_NUM 4 #define DEFAULT_OBJECT_POOL_TIMEOUT 3000 // ms template class HObjectFactory { public: static T* create() { return new T; } }; template> class HObjectPool { public: HObjectPool( int init_num = DEFAULT_OBJECT_POOL_INIT_NUM, int max_num = DEFAULT_OBJECT_POOL_MAX_NUM, int timeout = DEFAULT_OBJECT_POOL_TIMEOUT) : _max_num(max_num) , _timeout(timeout) { for (int i = 0; i < init_num; ++i) { T* p = TFactory::create(); if (p) { objects_.push_back(std::shared_ptr(p)); } } _object_num = objects_.size(); } ~HObjectPool() {} int ObjectNum() { return _object_num; } int IdleNum() { return objects_.size(); } int BorrowNum() { return ObjectNum() - IdleNum(); } std::shared_ptr TryBorrow() { std::shared_ptr pObj = NULL; std::lock_guard locker(mutex_); if (!objects_.empty()) { pObj = objects_.front(); objects_.pop_front(); } return pObj; } std::shared_ptr Borrow() { std::shared_ptr pObj = TryBorrow(); if (pObj) { return pObj; } std::unique_lock locker(mutex_); if (_object_num < _max_num) { ++_object_num; // NOTE: unlock to avoid TFactory::create block mutex_.unlock(); T* p = TFactory::create(); mutex_.lock(); if (!p) --_object_num; return std::shared_ptr(p); } if (_timeout > 0) { std::cv_status status = cond_.wait_for(locker, std::chrono::milliseconds(_timeout)); if (status == std::cv_status::timeout) { return NULL; } if (!objects_.empty()) { pObj = objects_.front(); objects_.pop_front(); return pObj; } else { // WARN: No idle object } } return pObj; } void Return(std::shared_ptr& pObj) { if (!pObj) return; std::lock_guard locker(mutex_); objects_.push_back(pObj); cond_.notify_one(); } bool Add(std::shared_ptr& pObj) { std::lock_guard locker(mutex_); if (_object_num >= _max_num) { return false; } objects_.push_back(pObj); ++_object_num; cond_.notify_one(); return true; } bool Remove(std::shared_ptr& pObj) { std::lock_guard locker(mutex_); auto iter = objects_.begin(); while (iter != objects_.end()) { if (*iter == pObj) { iter = objects_.erase(iter); --_object_num; return true; } else { ++iter; } } return false; } void Clear() { std::lock_guard locker(mutex_); objects_.clear(); _object_num = 0; } int _object_num; int _max_num; int _timeout; private: std::list> objects_; std::mutex mutex_; std::condition_variable cond_; }; template> class HPoolObject { public: typedef HObjectPool PoolType; HPoolObject(PoolType& pool) : pool_(pool) { sptr_ = pool_.Borrow(); } ~HPoolObject() { if (sptr_) { pool_.Return(sptr_); } } HPoolObject(const HPoolObject&) = delete; HPoolObject& operator=(const HPoolObject&) = delete; T* get() { return sptr_.get(); } operator bool() { return sptr_.get() != NULL; } T* operator->() { return sptr_.get(); } T operator*() { return *sptr_.get(); } private: PoolType& pool_; std::shared_ptr sptr_; }; #endif // HV_OBJECT_POOL_H_