184 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			184 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#ifndef HV_OBJECT_POOL_H_
 | 
						|
#define HV_OBJECT_POOL_H_
 | 
						|
 | 
						|
/*
 | 
						|
 * @usage unittest/objectpool_test.cpp
 | 
						|
 */
 | 
						|
 | 
						|
#include <list>
 | 
						|
#include <memory>
 | 
						|
#include <mutex>
 | 
						|
#include <condition_variable>
 | 
						|
 | 
						|
#define DEFAULT_OBJECT_POOL_INIT_NUM    0
 | 
						|
#define DEFAULT_OBJECT_POOL_MAX_NUM     4
 | 
						|
#define DEFAULT_OBJECT_POOL_TIMEOUT     3000 // ms
 | 
						|
 | 
						|
template<class T>
 | 
						|
class HObjectFactory {
 | 
						|
public:
 | 
						|
    static T* create() {
 | 
						|
        return new T;
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
template<class T, class TFactory = HObjectFactory<T>>
 | 
						|
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<T>(p));
 | 
						|
            }
 | 
						|
        }
 | 
						|
        _object_num = objects_.size();
 | 
						|
    }
 | 
						|
 | 
						|
    ~HObjectPool() {}
 | 
						|
 | 
						|
    int ObjectNum() { return _object_num; }
 | 
						|
    int IdleNum() { return objects_.size(); }
 | 
						|
    int BorrowNum() { return ObjectNum() - IdleNum(); }
 | 
						|
 | 
						|
    std::shared_ptr<T> TryBorrow() {
 | 
						|
        std::shared_ptr<T> pObj = NULL;
 | 
						|
        std::lock_guard<std::mutex> locker(mutex_);
 | 
						|
        if (!objects_.empty()) {
 | 
						|
            pObj = objects_.front();
 | 
						|
            objects_.pop_front();
 | 
						|
        }
 | 
						|
        return pObj;
 | 
						|
    }
 | 
						|
 | 
						|
    std::shared_ptr<T> Borrow() {
 | 
						|
        std::shared_ptr<T> pObj = TryBorrow();
 | 
						|
        if (pObj) {
 | 
						|
            return pObj;
 | 
						|
        }
 | 
						|
 | 
						|
        std::unique_lock<std::mutex> 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<T>(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<T>& pObj) {
 | 
						|
        if (!pObj) return;
 | 
						|
        std::lock_guard<std::mutex> locker(mutex_);
 | 
						|
        objects_.push_back(pObj);
 | 
						|
        cond_.notify_one();
 | 
						|
    }
 | 
						|
 | 
						|
    bool Add(std::shared_ptr<T>& pObj) {
 | 
						|
        std::lock_guard<std::mutex> 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<T>& pObj) {
 | 
						|
        std::lock_guard<std::mutex> 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<std::mutex> locker(mutex_);
 | 
						|
        objects_.clear();
 | 
						|
        _object_num = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    int     _object_num;
 | 
						|
    int     _max_num;
 | 
						|
    int     _timeout;
 | 
						|
private:
 | 
						|
    std::list<std::shared_ptr<T>>   objects_;
 | 
						|
    std::mutex              mutex_;
 | 
						|
    std::condition_variable cond_;
 | 
						|
};
 | 
						|
 | 
						|
template<class T, class TFactory = HObjectFactory<T>>
 | 
						|
class HPoolObject {
 | 
						|
public:
 | 
						|
    typedef HObjectPool<T, TFactory> PoolType;
 | 
						|
 | 
						|
    HPoolObject(PoolType& pool) : pool_(pool)
 | 
						|
    {
 | 
						|
        sptr_ = pool_.Borrow();
 | 
						|
    }
 | 
						|
 | 
						|
    ~HPoolObject() {
 | 
						|
        if (sptr_) {
 | 
						|
            pool_.Return(sptr_);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    HPoolObject(const HPoolObject<T>&) = delete;
 | 
						|
    HPoolObject<T>& operator=(const HPoolObject<T>&) = 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<T> sptr_;
 | 
						|
};
 | 
						|
 | 
						|
#endif // HV_OBJECT_POOL_H_
 |