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_
|