Browse Source

update HObjectPool

hewei.it 5 years ago
parent
commit
6eec386f95
2 changed files with 100 additions and 41 deletions
  1. 95 33
      base/hobjectpool.h
  2. 5 8
      unittest/objectpool_test.cpp

+ 95 - 33
base/hobjectpool.h

@@ -6,29 +6,44 @@
 #include <mutex>
 #include <condition_variable>
 
-#define DEFAULT_OBJECT_POOL_SIZE    4
-#define DEFAULT_GET_TIMEOUT         3000 // ms
+#define DEFAULT_OBJECT_POOL_INIT_NUM    0
+#define DEFAULT_OBJECT_POOL_MAX_NUM     4
+#define DEFAULT_OBJECT_POOL_TIMEOUT     3000 // ms
 
-template<typename T>
-class HObjectPool {
+template<class T>
+class HObjectFactory {
 public:
-    HObjectPool(int size = DEFAULT_OBJECT_POOL_SIZE)
-    : pool_size(size), timeout(DEFAULT_GET_TIMEOUT), object_num(0) {
+    static T* create() {
+        return new T;
     }
+};
 
-    ~HObjectPool() {
+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();
     }
 
-    virtual bool CreateObject(std::shared_ptr<T>& pObj) {
-        pObj = std::shared_ptr<T>(new T);
-        return true;
-    }
+    ~HObjectPool() {}
 
-    virtual bool InitObject(std::shared_ptr<T>& pObj) {
-        return true;
-    }
+    int ObjectNum() { return _object_num; }
+    int IdleNum() { return objects_.size(); }
+    int BorrowNum() { return ObjectNum() - IdleNum(); }
 
-    std::shared_ptr<T> TryGet() {
+    std::shared_ptr<T> TryBorrow() {
         std::shared_ptr<T> pObj = NULL;
         std::lock_guard<std::mutex> locker(mutex_);
         if (!objects_.empty()) {
@@ -38,22 +53,25 @@ public:
         return pObj;
     }
 
-    std::shared_ptr<T> Get() {
-        std::shared_ptr<T> pObj = TryGet();
+    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 < pool_size) {
-            if (CreateObject(pObj) && InitObject(pObj)) {
-                ++object_num;
-                return pObj;
-            }
+        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 (_timeout > 0) {
+            std::cv_status status = cond_.wait_for(locker, std::chrono::milliseconds(_timeout));
             if (status == std::cv_status::timeout) {
                 return NULL;
             }
@@ -63,24 +81,26 @@ public:
                 return pObj;
             }
             else {
-                // WARN: objects too little
+                // WARN: No idle object
             }
         }
         return pObj;
     }
 
-    void Release(std::shared_ptr<T>& 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 >= pool_size) {
+        if (_object_num >= _max_num) {
             return false;
         }
         objects_.push_back(pObj);
-        ++object_num;
+        ++_object_num;
         cond_.notify_one();
         return true;
     }
@@ -91,25 +111,67 @@ public:
         while (iter !=  objects_.end()) {
             if (*iter == pObj) {
                 iter = objects_.erase(iter);
-                --object_num;
+                --_object_num;
                 return true;
             }
+            else {
+                ++iter;
+            }
         }
         return false;
     }
 
-    void RemoveAll() {
+    void Clear() {
         std::lock_guard<std::mutex> locker(mutex_);
         objects_.clear();
+        _object_num = 0;
     }
 
-    int     pool_size;
-    int     timeout;
+    int     _object_num;
+    int     _max_num;
+    int     _timeout;
 private:
-    int                             object_num;
     std::list<std::shared_ptr<T>>   objects_;
     std::mutex              mutex_;
     std::condition_variable cond_;
 };
 
+template <typename T>
+class HPoolObject {
+public:
+    HPoolObject(HObjectPool<T>& 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:
+    HObjectPool<T>& pool_;
+    std::shared_ptr<T> sptr_;
+};
+
 #endif // HV_OBJECT_POOL_H_

+ 5 - 8
unittest/objectpool_test.cpp

@@ -29,24 +29,21 @@ public:
     }
 };
 
-HObjectPool<Task> tasks;
+HObjectPool<Task> task_pool(1, 5);
 
 void task_thread(int id) {
     printf("thread %d run...\n", id);
-    auto pObj = tasks.Get();
-    if (pObj) {
-        pObj->Do();
-        tasks.Release(pObj);
+    HPoolObject<Task> pTask(task_pool);
+    if (pTask) {
+        pTask->Do();
     }
     else {
-        printf("objects too little\n");
+        printf("No available task in pool\n");
     }
     printf("thread %d exit\n", id);
 }
 
 int main(int argc, char** argv) {
-    tasks.pool_size = 5;
-    tasks.timeout = 3000;
     for (int i = 0; i < 10; ++i) {
         new std::thread(task_thread, i);
     }