Browse Source

add HObjectPool

ithewei 6 years ago
parent
commit
16996c8402
4 changed files with 176 additions and 1 deletions
  1. 1 0
      Makefile
  2. 115 0
      base/hobjectpool.h
  3. 59 0
      unittest/objectpool_test.cpp
  4. 1 1
      utils/hendian.h

+ 1 - 0
Makefile

@@ -72,6 +72,7 @@ unittest: prepare
 	$(CC)  -std=c99   -I. -Ibase         -o bin/socketpair unittest/socketpair_test.c    base/hsocket.c base/htime.c
 	$(CXX) -std=c++11 -I. -Ibase         -o bin/defer      unittest/defer_test.cpp
 	$(CXX) -std=c++11 -I. -Ibase         -o bin/threadpool unittest/threadpool_test.cpp  -pthread
+	$(CXX) -std=c++11 -I. -Ibase         -o bin/objectpool unittest/objectpool_test.cpp  -pthread
 	$(CXX) -std=c++11 -I. -Ibase         -o bin/ls         unittest/listdir_test.cpp     base/hdir.cpp base/hbase.c
 	$(CXX) -std=c++11 -I. -Ibase -Iutils -o bin/ifconfig   unittest/ifconfig_test.cpp    utils/ifconfig.cpp
 

+ 115 - 0
base/hobjectpool.h

@@ -0,0 +1,115 @@
+#ifndef HW_OBJECT_POOL_H_
+#define HW_OBJECT_POOL_H_
+
+#include <list>
+#include <memory>
+#include <mutex>
+#include <condition_variable>
+
+#define DEFAULT_OBJECT_POOL_SIZE    4
+#define DEFAULT_GET_TIMEOUT         3000 // ms
+
+template<typename T>
+class HObjectPool {
+public:
+    HObjectPool(int size = DEFAULT_OBJECT_POOL_SIZE)
+    : pool_size(size), timeout(DEFAULT_GET_TIMEOUT), object_num(0) {
+    }
+
+    ~HObjectPool() {
+    }
+
+    virtual bool CreateObject(std::shared_ptr<T>& pObj) {
+        pObj = std::shared_ptr<T>(new T);
+        return true;
+    }
+
+    virtual bool InitObject(std::shared_ptr<T>& pObj) {
+        return true;
+    }
+
+    std::shared_ptr<T> TryGet() {
+        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> Get() {
+        std::shared_ptr<T> pObj = TryGet();
+        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 (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: objects too little
+            }
+        }
+        return pObj;
+    }
+
+    void Release(std::shared_ptr<T>& pObj) {
+        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) {
+            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;
+            }
+        }
+        return false;
+    }
+
+    void RemoveAll() {
+        std::lock_guard<std::mutex> locker(mutex_);
+        objects_.clear();
+    }
+
+    int     pool_size;
+    int     timeout;
+private:
+    int                             object_num;
+    std::list<std::shared_ptr<T>>   objects_;
+    std::mutex              mutex_;
+    std::condition_variable cond_;
+};
+
+#endif // HW_OBJECT_POOL_H_

+ 59 - 0
unittest/objectpool_test.cpp

@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <thread>
+
+#include "hobjectpool.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+void msleep(unsigned int ms) {
+#ifdef _WIN32
+    Sleep(ms);
+#else
+    usleep(ms*1000);
+#endif
+}
+
+class Task {
+public:
+    Task() {printf("Task()\n");}
+    ~Task() {printf("~Task()\n");}
+
+    void Do() {
+        printf("%p start do...\n", this);
+        msleep(4000);
+        printf("%p end do\n", this);
+    }
+};
+
+HObjectPool<Task> tasks;
+
+void task_thread(int id) {
+    printf("thread %d run...\n", id);
+    auto pObj = tasks.Get();
+    if (pObj) {
+        pObj->Do();
+        tasks.Release(pObj);
+    }
+    else {
+        printf("objects too little\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);
+    }
+    msleep(5000);
+    for (int i = 10; i < 20; ++i) {
+        new std::thread(task_thread, i);
+    }
+    msleep(10000);
+    return 0;
+}

+ 1 - 1
utils/hendian.h

@@ -7,7 +7,7 @@
 #include "hplatform.h"
 #include "hdef.h"
 
-int detect_endian() {
+static inline int detect_endian() {
     union {
         char c;
         short s;