RCFProto

- Main Page
- Classes
- Files

- File List

All Classes Functions Typedefs
ObjectPool.hpp
1
2 //******************************************************************************
3 // RCF - Remote Call Framework
4 //
5 // Copyright (c) 2005 - 2013, Delta V Software. All rights reserved.
6 // http://www.deltavsoft.com
7 //
8 // RCF is distributed under dual licenses - closed source or GPL.
9 // Consult your particular license for conditions of use.
10 //
11 // If you have not purchased a commercial license, you are using RCF
12 // under GPL terms.
13 //
14 // Version: 2.0
15 // Contact: support <at> deltavsoft.com
16 //
17 //******************************************************************************
18
19 #ifndef INCLUDE_RCF_OBJECTPOOL_HPP
20 #define INCLUDE_RCF_OBJECTPOOL_HPP
21
22 #include <vector>
23
24 #include <boost/bind.hpp>
25 #include <boost/shared_ptr.hpp>
26
27 #include <RCF/Tools.hpp>
28 #include <RCF/ThreadLibrary.hpp>
29
30 namespace RCF {
31
32 static const std::size_t CbSize = 128;
33
34 class ObjectPool;
35
36 class RCF_EXPORT CbAllocatorBase
37 {
38 public:
39
40 CbAllocatorBase(ObjectPool & objectPool);
41 CbAllocatorBase(const CbAllocatorBase & rhs);
42
43 void * allocate();
44 void deallocate(void * pcb) ;
45
46 private:
47 ObjectPool & mObjectPool;
48 };
49
50 template<typename T>
51 class CbAllocator : public CbAllocatorBase
52 {
53 public:
54
55 typedef T value_type;
56 typedef value_type* pointer;
57 typedef std::size_t size_type;
58 typedef std::ptrdiff_t difference_type;
59
60 template<typename U>
61 struct rebind
62 {
63 typedef CbAllocator<U> other;
64 };
65
66 CbAllocator(ObjectPool & objectPool) : CbAllocatorBase(objectPool)
67 {
68 }
69
70 template<typename U>
71 CbAllocator( const CbAllocator<U> & rhs) : CbAllocatorBase(rhs)
72 {
73 }
74
75 pointer allocate(
76 size_type cnt,
77 typename std::allocator<void>::const_pointer = 0)
78 {
79 BOOST_STATIC_ASSERT( sizeof(T) <= CbSize );
80 RCF_ASSERT_EQ(cnt , 1);
81 return reinterpret_cast<pointer>(CbAllocatorBase::allocate());
82 }
83
84 void deallocate(pointer p, size_type)
85 {
86 CbAllocatorBase::deallocate(p);
87 }
88 };
89
90 class TypeInfo
91 {
92 public:
93 TypeInfo(const std::type_info & ti) : mpTypeInfo(&ti)
94 {
95
96 }
97
98 bool operator<(const TypeInfo & rhs) const
99 {
100 return (*mpTypeInfo).before(*rhs.mpTypeInfo) ? true : false;
101 }
102
103 private:
104 const std::type_info * mpTypeInfo;
105 };
106
107 class ReallocBuffer;
108 typedef boost::shared_ptr<ReallocBuffer> ReallocBufferPtr;
109
110 class RCF_EXPORT ObjectPool
111 {
112 public:
113
114 ObjectPool();
115 ~ObjectPool();
116
117 template<typename T>
118 void enableCaching(std::size_t maxCount, boost::function1<void, T *> clearFunc)
119 {
120 enableCaching( (T *) NULL, maxCount, clearFunc);
121 }
122
123 template<typename T>
124 void disableCaching()
125 {
126 disableCaching( (T *) NULL);
127 }
128
129 template<typename T>
130 void enableCaching(T *, std::size_t maxCount, boost::function1<void, T *> clearFunc)
131 {
132 RCF::WriteLock lock(mObjPoolMutex);
133 RCF::TypeInfo ti( typeid(T) );
134 mObjPool[ti].reset( new RCF::ObjectPool::ObjList() );
135 mObjPool[ti]->mMaxSize = maxCount;
136 mObjPool[ti]->mOps.reset( new RCF::ObjectPool::Ops<T>(clearFunc) );
137 }
138
139 template<typename T>
140 void disableCaching(T *)
141 {
142 RCF::WriteLock lock(mObjPoolMutex);
143 RCF::TypeInfo ti( typeid(T) );
144 mObjPool[ti]->mMaxSize = 0;
145 mObjPool[ti]->clear();
146 }
147
148 template<typename T>
149 bool isCachingEnabled(T *)
150 {
151 ReadLock lock(mObjPoolMutex);
152 if (!mObjPool.empty())
153 {
154 RCF::TypeInfo ti( typeid(T) );
155 ObjPool::iterator iter = mObjPool.find(ti);
156 if (iter != mObjPool.end())
157 {
158 if (iter->second->mMaxSize > 0)
159 {
160 return true;
161 }
162 }
163 }
164 return false;
165 }
166
167 MemOstreamPtr getMemOstreamPtr();
168 ReallocBufferPtr getReallocBufferPtr();
169
170 void enumerateWriteBuffers(std::vector<std::size_t> & bufferSizes);
171 void enumerateReadBuffers(std::vector<std::size_t> & bufferSizes);
172
173 void setBufferCountLimit(std::size_t bufferCountLimit);
174 std::size_t getBufferCountLimit();
175
176 void setBufferSizeLimit(std::size_t bufferSizeLimit);
177 std::size_t getBufferSizeLimit();
178
179 template<typename T>
180 void getObj(boost::shared_ptr<T> & objPtr, bool alwaysCreate = true)
181 {
182 T * pt = NULL;
183 void * pv = NULL;
184 boost::shared_ptr<void> spv;
185 bool pfnDeleter = false;
186
187
188 {
189 ReadLock lock(mObjPoolMutex);
190
191 if (mObjPool.empty())
192 {
193 if (alwaysCreate)
194 {
195 pt = new T;
196 }
197 else
198 {
199 return;
200 }
201 }
202 else
203 {
204 TypeInfo ti( typeid(T) );
205 ObjPool::iterator iter = mObjPool.find(ti);
206 if (iter == mObjPool.end())
207 {
208 if (alwaysCreate)
209 {
210 pt = new T;
211 }
212 else
213 {
214 return;
215 }
216 }
217 else
218 {
219 ObjList & objList = *(iter->second);
220 Lock lock(objList.mMutex);
221 if (objList.mMaxSize == 0)
222 {
223 if (alwaysCreate)
224 {
225 pt = new T;
226 }
227 else
228 {
229 return;
230 }
231 }
232 else if (objList.mVec.empty())
233 {
234 pt = new T;
235 pfnDeleter = true;
236 }
237 else
238 {
239 pv = objList.mVec.back();
240 pt = static_cast<T *>(pv);
241 objList.mVec.pop_back();
242 pfnDeleter = true;
243 }
244 }
245 }
246 }
247
248 RCF_ASSERT(pt);
249 if (pfnDeleter)
250 {
251 TypeInfo ti( typeid(T) );
252
253 #if BOOST_VERSION < 103400
254
255 // 1.33.1 shared_ptr, and earlier, does not have allocator support. Consequently we
256 // have a (small) allocation each time a buffer is requested, and a corresponding
257 // deallocation when the buffer is returned to the pool.
258
259 objPtr = boost::shared_ptr<T>(
260 pt,
261 boost::bind(&ObjectPool::putObj, this, ti, _1));
262
263 #else
264
265 // 1.34.0 shared_ptr has allocator support. Consequently we have no allocations
266 // at all when a buffer is requested.
267
268 objPtr = boost::shared_ptr<T>(
269 pt,
270 boost::bind(&ObjectPool::putObj, this, ti, _1),
271 CbAllocator<void>(*this) );
272
273 #endif
274 }
275 else
276 {
277 objPtr = boost::shared_ptr<T>(pt);
278 }
279 }
280
281 void putObj(const TypeInfo & ti, void * pv)
282 {
283 ReadLock readLock(mObjPoolMutex);
284 RCF_ASSERT(!mObjPool.empty());
285 ObjPool::iterator iter = mObjPool.find(ti);
286 RCF_ASSERT(iter != mObjPool.end());
287 ObjList & objList = *(iter->second);
288 Lock lock(objList.mMutex);
289 if (objList.mVec.size() >= objList.mMaxSize)
290 {
291 lock.unlock();
292 readLock.unlock();
293 objList.mOps->kill(pv);
294 }
295 else
296 {
297 objList.mOps->clear(pv);
298 objList.mVec.push_back(pv);
299 }
300 }
301
302 class I_Ops
303 {
304 public:
305 virtual ~I_Ops() {}
306 virtual void kill(void * pv) = 0;
307 virtual void clear(void * pv) = 0;
308 };
309
310 template<typename T>
311 class Ops : public I_Ops
312 {
313 public:
314 Ops(boost::function1<void, T *> clearFunc) :
315 mClearFunc(clearFunc)
316 {
317 }
318
319 void kill(void * pv)
320 {
321 T * pt = static_cast<T *>(pv);
322 delete pt;
323 }
324
325 void clear(void * pv)
326 {
327 if (mClearFunc)
328 {
329 T * pt = static_cast<T *>(pv);
330 mClearFunc(pt);
331 }
332 }
333
334 boost::function1<void, T *> mClearFunc;
335 };
336
337 class ObjList : boost::noncopyable
338 {
339 public:
340 ObjList() : mMaxSize(0)
341 {
342 }
343 Mutex mMutex;
344 std::size_t mMaxSize;
345 std::vector<void *> mVec;
346 boost::scoped_ptr<I_Ops> mOps;
347
348 void clear()
349 {
350 for (std::size_t i=0; i<mVec.size(); ++i)
351 {
352 mOps->kill(mVec[i]);
353 }
354 mVec.clear();
355 }
356 };
357
358 typedef boost::shared_ptr<ObjList> ObjListPtr;
359
360 typedef std::map< TypeInfo, ObjListPtr > ObjPool;
361 ReadWriteMutex mObjPoolMutex;
362 ObjPool mObjPool;
363
364 private:
365
366 friend class CbAllocatorBase;
367
368 void * getPcb();
369 void putPcb(void * pcb);
370
371 void putMemOstream(MemOstream * pOs);
372 void putReallocBuffer(ReallocBuffer * pRb);
373
374 std::size_t mBufferCountLimit;
375 std::size_t mBufferSizeLimit;
376
377 Mutex mOsPoolMutex;
378 std::vector< MemOstream * > mOsPool;
379
380 Mutex mRbPoolMutex;
381 std::vector< ReallocBuffer * > mRbPool;
382
383 Mutex mCbPoolMutex;
384 std::vector< void * > mCbPool;
385
386 template<typename T, typename Spt, typename PtrList, typename Pfn>
387 void getPtr(
388 T *,
389 Spt & spt,
390 PtrList & ptrList,
391 Mutex & ptrListMutex,
392 Pfn pfn)
393 {
394 T * pt = NULL;
395
396 {
397 Lock lock(ptrListMutex);
398
399 if (ptrList.empty())
400 {
401 pt = new T();
402 }
403 else
404 {
405 pt = ptrList.back();
406 ptrList.pop_back();
407 }
408 }
409
410 #if BOOST_VERSION < 103400
411
412 // 1.33.1 shared_ptr, and earlier, does not have allocator support. Consequently we
413 // have a (small) allocation each time a buffer is requested, and a corresponding
414 // deallocation when the buffer is returned to the pool.
415
416 spt = boost::shared_ptr<T>(
417 pt,
418 boost::bind(pfn, this, _1));
419
420 #else
421
422 // 1.34.0 shared_ptr has allocator support. Consequently we have no allocations
423 // at all when a buffer is requested.
424
425 spt = boost::shared_ptr<T>(
426 pt,
427 boost::bind(pfn, this, _1),
428 CbAllocator<void>(*this) );
429
430 #endif
431
432 }
433
434 };
435
436 RCF_EXPORT ObjectPool & getObjectPool();
437
438 } // namespace RCF
439
440 #endif // ! INCLUDE_RCF_OBJECTPOOL_HPP