對象池的設計及其實現

對象池概述:

對象池模型建立並擁有固定數量的對象,當程序須要一個新的對象時,若是對象池中有空閒對象,則當即返回,不然才建立新的該類對象。當一個對象再也不被使用時,其應該應該將其放回對象池,以便後來的程序使用。因爲系統資源有限,一個對象池模型應該指定其可容納的最大對象數量。當達到該數量時,若是仍然有對象建立請求,則拋出異常或者阻塞當前調用線程,直到一個對象被放回對象池中。數據庫

 

對象池模型適用的場景:

(1)須要使用大量對象網絡

(2)這些對象的實例化開銷比較大且生存期比較短ide

 

對象池優點:

一個對象池能夠在可容忍時間內建立成功並投入使用。可是建立對象時並不老是這樣,尤爲是當這些對象的建立過程比較耗時,並且建立和銷燬頻率又比較大時更是如此。好比數據庫鏈接、網絡套接字鏈接、線程對象、諸如字體或位圖等圖像對象等。函數

 

實現:

假設有以下類定義:測試

 1 class Object
 2 {
 3 public:
 4     Object(const string& name) : name_(name)
 5     {
 6         printf("Construct Object[%p] %s.\n", this, name_.c_str());
 7     }
 8 
 9     ~Object()
10     {
11         printf("~Destruct Object[%p] %s.\n", this, name_.c_str());
12     }
13 
14     const string& key() const { return name_; }
15 
16 private:
17     string name_;
18 };

以下對象池類的設計,用來提供Object類對象,分爲2個版本介紹:(注意,以下僅考慮了對象池自己所涉及的特性,沒有涉及同步控制機制)字體

版本1this

 1 class ObjectPool
 2 {
 3 public:
 4     boost::shared_ptr<Object> get(const string& key)
 5     {
 6         boost::shared_ptr<Object> pObject;
 7         boost::weak_ptr<Object>& k_object = objects_[key];
 8         pObject = k_object.lock();
 9         if (!pObject)
10         {
11             pObject.reset(new Object(key),
12                          boost::bind(&ObjectPool::releaseObject, this, _1));
13             k_object = pObject;
14         }
15         return pObject;
16   }
17 
18 private:
19     void releaseObject(Object* object)
20     {
21         printf("releaseObject[%p].\n", object);
22         if (object)
23         {
24             objects_.erase(object->key());
25         }
26         delete object;
27     }
28 
29     std::map<string, boost::weak_ptr<Object> > objects_;
30 };

ObjectPool的get函數返回map中key對應的Object對象。若是該對象不存在,則新建一個Object,將其放入map中,而後返回這個新建的Object。同時,重置shared_ptr(新增Object對象)時指定析構器releaseObject,使得對象析構時執行releaseObject(object);spa

可是上述實現存在一個問題:將this傳入bind函數中,若是ObjectPool對象先於Object對象析構了,那麼在析構Object對象時,如何調用releaseObject函數呢?(由於releaseObject函數屬於ObjectPool類)線程

版本2設計

 1 class ObjectPool : public boost::enable_shared_from_this<ObjectPool>
 2 {
 3 public:
 4     boost::shared_ptr<Object> get(const string& key)
 5     {
 6         boost::shared_ptr<Object> pObject;
 7         boost::weak_ptr<Object>& k_object = objects_[key];
 8         pObject = k_object.lock();
 9         if (!pObject)
10         {
11             pObject.reset(new Object(key),
12                          boost::bind(&ObjectPool::releaseObject, shared_from_this(), _1));
13             k_object = pObject;
14         }
15         return pObject;
16   }
17 
18 private:
19     void releaseObject(Object* object)
20     {
21         printf("releaseObject[%p].\n", object);
22         if (object)
23         {
24             objects_.erase(object->key());
25         }
26         delete object;
27     }
28 
29     std::map<string, boost::weak_ptr<Object> > objects_;
30 };

要解決版本1中的問題,只需增長ObjectPool的壽命就能夠了。能夠利用boost::enable_shared_from_this模板類中的shared_from_this(),如此能夠將this轉換爲shared_ptr<ObjectPool>。如此,因爲bind是值傳遞語義,所以其必然保存一份shared_ptr<ObjectPool>的副本,能夠保證shared_ptr的引用計數不爲0。

 

測試用例: 

  1 // object_pool.cc
  2 #include <map>
  3 
  4 #include <boost/bind.hpp>
  5 #include <boost/enable_shared_from_this.hpp>
  6 #include <boost/shared_ptr.hpp>
  7 #include <boost/weak_ptr.hpp>
  8 
  9 #include <stdio.h>
 10 
 11 using std::string;
 12 const int MAXNUM = 5;  // the largest amounts of objects
 13 int nums = 0;          // the current amounts of objects
 14 
 15 class Object
 16 {
 17 public:
 18     Object(const string& name) : name_(name)
 19     {
 20         printf("Construct Object[%p] %s.\n", this, name_.c_str());
 21     }
 22 
 23     ~Object()
 24     {
 25         printf("~Destruct Object[%p] %s.\n", this, name_.c_str());
 26     }
 27 
 28     const string& key() const { return name_; }
 29 
 30 private:
 31     string name_;
 32 };
 33 
 34 
 35 namespace version1
 36 {
 37 
 38 class ObjectPool
 39 {
 40 public:
 41     boost::shared_ptr<Object> get(const string& key)
 42     {
 43         boost::shared_ptr<Object> pObject;
 44         boost::weak_ptr<Object>& k_object = objects_[key];
 45         pObject = k_object.lock();
 46         if (!pObject)
 47         {
 48             ++nums;
 49             BOOST_ASSERT(nums <= MAXNUM);
 50             pObject.reset(new Object(key),
 51                          boost::bind(&ObjectPool::releaseObject, this, _1));
 52             k_object = pObject;
 53         }
 54         return pObject;
 55   }
 56 
 57 private:
 58     void releaseObject(Object* object)
 59     {
 60         printf("releaseObject[%p].\n", object);
 61         if (object)
 62         {
 63             --nums;
 64             objects_.erase(object->key());
 65         }
 66         delete object;
 67     }
 68 
 69     std::map<string, boost::weak_ptr<Object> > objects_;
 70 };
 71 
 72 }
 73 
 74 namespace version2
 75 {
 76 
 77 class ObjectPool : public boost::enable_shared_from_this<ObjectPool>
 78 {
 79 public:
 80     boost::shared_ptr<Object> get(const string& key)
 81     {
 82         boost::shared_ptr<Object> pObject;
 83         boost::weak_ptr<Object>& k_object = objects_[key];
 84         pObject = k_object.lock();
 85         if (!pObject)
 86         {
 87             ++nums;
 88             BOOST_ASSERT(nums <= MAXNUM);
 89             pObject.reset(new Object(key),
 90                          boost::bind(&ObjectPool::releaseObject, shared_from_this(), _1));
 91             k_object = pObject;
 92         }
 93         return pObject;
 94   }
 95 
 96 private:
 97     void releaseObject(Object* object)
 98     {
 99         printf("releaseObject[%p].\n", object);
100         if (object)
101         {
102             --nums;
103             objects_.erase(object->key());
104         }
105         delete object;
106     }
107 
108     std::map<string, boost::weak_ptr<Object> > objects_;
109 };
110 
111 }
112 
113 
114 int main()
115 {
116     boost::shared_ptr<version1::ObjectPool> op1(new version1::ObjectPool);
117 
118     boost::shared_ptr<Object> object1 = op1->get("object1");
119     boost::shared_ptr<Object> object2 = op1->get("object2");
120     boost::shared_ptr<Object> object3 = op1->get("object3");
121     boost::shared_ptr<Object> object4 = op1->get("object4");
122     boost::shared_ptr<Object> object5 = op1->get("object5");
123     boost::shared_ptr<Object> object6 = op1->get("object5");
124 
125     //boost::shared_ptr<version2::ObjectPool> op2(new version2::ObjectPool);
126     //boost::shared_ptr<Object> object7 = op2->get("object2");
127     //boost::shared_ptr<Object> object8 = op2->get("object2");
128 
129     return 0;
130 }
131 
132 // output
133 Construct Object[003e1060] object1.
134 Construct Object[003e10e0] object2.
135 Construct Object[003e1160] object3.
136 Construct Object[003e11e0] object4.
137 Construct Object[003e1260] object5.
138 releaseObject[003e1260].
139 ~Destruct Object[003e1260] object5.
140 releaseObject[003e11e0].
141 ~Destruct Object[003e11e0] object4.
142 releaseObject[003e1160].
143 ~Destruct Object[003e1160] object3.
144 releaseObject[003e10e0].
145 ~Destruct Object[003e10e0] object2.
146 releaseObject[003e1060].
147 ~Destruct Object[003e1060] object1.
View Code

 

References

https://en.wikipedia.org/wiki/Object_pool_pattern

相關文章
相關標籤/搜索