内存池

  1 #ifndef PPX_BASE_MEMORY_POOL_H_
  2 #define PPX_BASE_MEMORY_POOL_H_
  3 
  4 #include <climits>
  5 #include <cstddef>
  6 #include <mutex>
  7 
  8 namespace ppx {
  9     namespace base {
 10         template <typename T, size_t BlockSize = 4096, bool ZeroOnDeallocate = true>
 11         class MemoryPool {
 12         public:
 13             /* Member types */
 14             typedef T               value_type;
 15             typedef T*              pointer;
 16             typedef T&              reference;
 17             typedef const T*        const_pointer;
 18             typedef const T&        const_reference;
 19             typedef size_t          size_type;
 20             typedef ptrdiff_t       difference_type;
 21             typedef std::false_type propagate_on_container_copy_assignment;
 22             typedef std::true_type  propagate_on_container_move_assignment;
 23             typedef std::true_type  propagate_on_container_swap;
 24 
 25             template <typename U> struct rebind {
 26                 typedef MemoryPool<U> other;
 27             };
 28 
 29             /* Member functions */
 30             MemoryPool() noexcept;
 31             MemoryPool(const MemoryPool& memoryPool) noexcept;
 32             MemoryPool(MemoryPool&& memoryPool) noexcept;
 33             template <class U> MemoryPool(const MemoryPool<U>& memoryPool) noexcept;
 34 
 35             ~MemoryPool() noexcept;
 36 
 37             MemoryPool& operator=(const MemoryPool& memoryPool) = delete;
 38             MemoryPool& operator=(MemoryPool&& memoryPool) noexcept;
 39 
 40             pointer address(reference x) const noexcept;
 41             const_pointer address(const_reference x) const noexcept;
 42 
 43             // Can only allocate one object at a time. n and hint are ignored
 44             pointer allocate(size_type n = 1, const_pointer hint = 0);
 45             void deallocate(pointer p, size_type n = 1);
 46 
 47             size_type max_size() const noexcept;
 48 
 49             template <class U, class... Args> void construct(U* p, Args&&... args);
 50             template <class U> void destroy(U* p);
 51 
 52             template <class... Args> pointer newElement(Args&&... args);
 53             void deleteElement(pointer p);
 54 
 55         private:
 56             struct Element_ {
 57                 Element_* pre;
 58                 Element_* next;
 59             };
 60 
 61             typedef char* data_pointer;
 62             typedef Element_ element_type;
 63             typedef Element_* element_pointer;
 64 
 65             element_pointer data_element_;
 66             element_pointer free_element_;
 67 
 68             std::recursive_mutex m_;
 69 
 70             size_type padPointer(data_pointer p, size_type align) const noexcept;
 71             void allocateBlock();
 72 
 73             static_assert(BlockSize >= 2 * sizeof(element_type), "BlockSize too small.");
 74         };
 75 
 76 
 77         template <typename T, size_t BlockSize,  bool ZeroOnDeallocate>
 78         inline typename MemoryPool<T, BlockSize, ZeroOnDeallocate>::size_type
 79             MemoryPool<T, BlockSize, ZeroOnDeallocate>::padPointer(data_pointer p, size_type align)
 80             const noexcept {
 81             uintptr_t result = reinterpret_cast<uintptr_t>(p);
 82             return ((align - result) % align);
 83         }
 84 
 85 
 86 
 87         template <typename T, size_t BlockSize,  bool ZeroOnDeallocate>
 88         MemoryPool<T, BlockSize, ZeroOnDeallocate>::MemoryPool()
 89             noexcept {
 90             data_element_ = nullptr;
 91             free_element_ = nullptr;
 92         }
 93 
 94         template <typename T, size_t BlockSize,  bool ZeroOnDeallocate>
 95         MemoryPool<T, BlockSize, ZeroOnDeallocate>::MemoryPool(const MemoryPool& memoryPool)
 96             noexcept :
 97             MemoryPool() {
 98         }
 99 
100         template <typename T, size_t BlockSize,  bool ZeroOnDeallocate>
101         MemoryPool<T, BlockSize, ZeroOnDeallocate>::MemoryPool(MemoryPool&& memoryPool)
102             noexcept {
103             std::lock_guard<std::recursive_mutex> lock(m_);
104 
105             data_element_ = memoryPool.data_element_;
106             memoryPool.data_element_ = nullptr;
107             free_element_ = memoryPool.free_element_;
108             memoryPool.free_element_ = nullptr;
109         }
110 
111         template <typename T, size_t BlockSize,  bool ZeroOnDeallocate>
112         template<class U>
113         MemoryPool<T, BlockSize, ZeroOnDeallocate>::MemoryPool(const MemoryPool<U>& memoryPool)
114             noexcept :
115             MemoryPool() {
116         }
117 
118         template <typename T, size_t BlockSize,  bool ZeroOnDeallocate>
119         MemoryPool<T, BlockSize, ZeroOnDeallocate>&
120             MemoryPool<T, BlockSize, ZeroOnDeallocate>::operator=(MemoryPool&& memoryPool)
121             noexcept {
122             std::lock_guard<std::recursive_mutex> lock(m_);
123 
124             if (this != &memoryPool) {
125                 std::swap(data_element_, memoryPool.data_element_);
126                 std::swap(free_element_, memoryPool.free_element_);
127             }
128             return *this;
129         }
130 
131         template <typename T, size_t BlockSize,  bool ZeroOnDeallocate>
132         MemoryPool<T, BlockSize, ZeroOnDeallocate>::~MemoryPool()
133             noexcept {
134             std::lock_guard<std::recursive_mutex> lock(m_);
135 
136             element_pointer curr = data_element_;
137             while (curr != nullptr) {
138                 element_pointer prev = curr->next;
139                 operator delete(reinterpret_cast<void*>(curr));
140                 curr = prev;
141             }
142 
143             curr = free_element_;
144             while (curr != nullptr) {
145                 element_pointer prev = curr->next;
146                 operator delete(reinterpret_cast<void*>(curr));
147                 curr = prev;
148             }
149         }
150 
151         template <typename T, size_t BlockSize,  bool ZeroOnDeallocate>
152         inline typename MemoryPool<T, BlockSize, ZeroOnDeallocate>::pointer
153             MemoryPool<T, BlockSize, ZeroOnDeallocate>::address(reference x)
154             const noexcept {
155             return &x;
156         }
157 
158         template <typename T, size_t BlockSize,  bool ZeroOnDeallocate>
159         inline typename MemoryPool<T, BlockSize, ZeroOnDeallocate>::const_pointer
160             MemoryPool<T, BlockSize, ZeroOnDeallocate>::address(const_reference x)
161             const noexcept {
162             return &x;
163         }
164 
165         template <typename T, size_t BlockSize,  bool ZeroOnDeallocate>
166         void
167             MemoryPool<T, BlockSize, ZeroOnDeallocate>::allocateBlock() {
168             // Allocate space for the new block and store a pointer to the previous one
169             data_pointer new_block = reinterpret_cast<data_pointer> (operator new(BlockSize));
170             element_pointer new_ele_pointer = reinterpret_cast<element_pointer>(new_block);
171             new_ele_pointer->pre = nullptr;
172             new_ele_pointer->next = nullptr;
173 
174             if (data_element_) {
175                 data_element_->pre = new_ele_pointer;
176             }
177 
178             new_ele_pointer->next = data_element_;
179             data_element_ = new_ele_pointer;
180         }
181 
182         template <typename T, size_t BlockSize,  bool ZeroOnDeallocate>
183         inline typename MemoryPool<T, BlockSize, ZeroOnDeallocate>::pointer
184             MemoryPool<T, BlockSize, ZeroOnDeallocate>::allocate(size_type n, const_pointer hint) {
185             std::lock_guard<std::recursive_mutex> lock(m_);
186 
187             if (free_element_ != nullptr) {
188                 data_pointer body =
189                     reinterpret_cast<data_pointer>(reinterpret_cast<data_pointer>(free_element_) + sizeof(element_type));
190 
191                 size_type bodyPadding = padPointer(body, alignof(element_type));
192 
193                 pointer result = reinterpret_cast<pointer>(reinterpret_cast<data_pointer>(body + bodyPadding));
194 
195                 element_pointer tmp = free_element_;
196 
197                 free_element_ = free_element_->next;
198 
199                 if (free_element_)
200                     free_element_->pre = nullptr;
201 
202                 tmp->next = data_element_;
203                 if (data_element_)
204                     data_element_->pre = tmp;
205                 tmp->pre = nullptr;
206                 data_element_ = tmp;
207 
208                 return result;
209             }
210             else {
211                 allocateBlock();
212 
213                 data_pointer body =
214                     reinterpret_cast<data_pointer>(reinterpret_cast<data_pointer>(data_element_) + sizeof(element_type));
215 
216                 size_type bodyPadding = padPointer(body, alignof(element_type));
217 
218                 pointer result = reinterpret_cast<pointer>(reinterpret_cast<data_pointer>(body + bodyPadding));
219 
220                 return result;
221             }
222         }
223 
224         template <typename T, size_t BlockSize, bool ZeroOnDeallocate>
225         inline void
226             MemoryPool<T, BlockSize, ZeroOnDeallocate>::deallocate(pointer p, size_type n) {
227             std::lock_guard<std::recursive_mutex> lock(m_);
228 
229             if (p != nullptr) {
230                 element_pointer ele_p =
231                     reinterpret_cast<element_pointer>(reinterpret_cast<data_pointer>(p) - sizeof(element_type));
232 
233                 if (ZeroOnDeallocate) {
234                     memset(reinterpret_cast<data_pointer>(p), 0, BlockSize - sizeof(element_type));
235                 }
236 
237                 if (ele_p->pre) {
238                     ele_p->pre->next = ele_p->next;
239                 }
240 
241                 if (ele_p->next) {
242                     ele_p->next->pre = ele_p->pre;
243                 }
244 
245                 if (ele_p->pre == nullptr) {
246                     data_element_ = ele_p->next;
247                 }
248 
249                 ele_p->pre = nullptr;
250                 if (free_element_) {
251                     ele_p->next = free_element_;
252                     free_element_->pre = ele_p;
253                 }
254                 else {
255                     ele_p->next = nullptr;
256                 }
257                 free_element_ = ele_p;
258             }
259         }
260 
261         template <typename T, size_t BlockSize, bool ZeroOnDeallocate>
262         inline typename MemoryPool<T, BlockSize, ZeroOnDeallocate>::size_type
263             MemoryPool<T, BlockSize, ZeroOnDeallocate>::max_size()
264             const noexcept {
265             size_type maxBlocks = -1 / BlockSize;
266             return (BlockSize - sizeof(data_pointer)) / sizeof(element_type) * maxBlocks;
267         }
268 
269         template <typename T, size_t BlockSize, bool ZeroOnDeallocate>
270         template <class U, class... Args>
271         inline void
272             MemoryPool<T, BlockSize, ZeroOnDeallocate>::construct(U* p, Args&&... args) {
273             new (p) U(std::forward<Args>(args)...);
274         }
275 
276         template <typename T, size_t BlockSize, bool ZeroOnDeallocate>
277         template <class U>
278         inline void
279             MemoryPool<T, BlockSize, ZeroOnDeallocate>::destroy(U* p) {
280             p->~U();
281         }
282 
283         template <typename T, size_t BlockSize, bool ZeroOnDeallocate>
284         template <class... Args>
285         inline typename MemoryPool<T, BlockSize, ZeroOnDeallocate>::pointer
286             MemoryPool<T, BlockSize, ZeroOnDeallocate>::newElement(Args&&... args) {
287             std::lock_guard<std::recursive_mutex> lock(m_);
288             pointer result = allocate();
289             construct<value_type>(result, std::forward<Args>(args)...);
290             return result;
291         }
292 
293         template <typename T, size_t BlockSize, bool ZeroOnDeallocate>
294         inline void
295             MemoryPool<T, BlockSize, ZeroOnDeallocate>::deleteElement(pointer p) {
296             std::lock_guard<std::recursive_mutex> lock(m_);
297             if (p != nullptr) {
298                 p->~value_type();
299                 deallocate(p);
300             }
301         }
302     }
303 }
304 
305 #endif // PPX_BASE_MEMORY_POOL_H_
306 
307 
308 使用示例:
309 #include <iostream>
310 #include <thread>
311 using namespace std;
312 class Apple {
313 public:
314     Apple() {
315         id_ = 0;
316         cout << "Apple()" << endl;
317     }
318 
319     Apple(int id) {
320         id_ = id;
321         cout << "Apple(" << id_ << ")" << endl;
322     }
323 
324     ~Apple() {
325         cout << "~Apple()" << endl;
326     }
327 
328     void SetId(int id) {
329         id_ = id;
330     }
331 
332     int GetId() {
333         return id_;
334     }
335 private:
336     int id_;
337 };
338 
339 
340 
341 void ThreadProc(ppx::base::MemoryPool<char> *mp) {
342     int i = 0;
343     while (i++ < 100000) {
344         char* p0 = (char*)mp->allocate();
345 
346         char* p1 = (char*)mp->allocate();
347 
348         mp->deallocate(p0);
349 
350         char* p2 = (char*)mp->allocate();
351 
352         mp->deallocate(p1);
353         
354         mp->deallocate(p2);
355 
356     }
357 }
358 
359 int main()
360 {
361     ppx::base::MemoryPool<char> mp;
362     int i = 0;
363     while (i++ < 100000) {
364         char* p0 = (char*)mp.allocate();
365 
366         char* p1 = (char*)mp.allocate();
367 
368         mp.deallocate(p0);
369 
370         char* p2 = (char*)mp.allocate();
371 
372         mp.deallocate(p1);
373 
374         mp.deallocate(p2);
375 
376     }
377 
378     std::thread th0(ThreadProc, &mp);
379     std::thread th1(ThreadProc, &mp);
380     std::thread th2(ThreadProc, &mp);
381 
382     th0.join();
383     th1.join();
384     th2.join();
385 
386     Apple *apple = nullptr;
387     {
388         ppx::base::MemoryPool<Apple> mp2;
389         apple = mp2.newElement(10);
390         int a = apple->GetId();
391         apple->SetId(10);
392         a = apple->GetId();
393 
394         mp2.deleteElement(apple);
395     }
396 
397     apple->SetId(12);
398     int b = -4 % 4;
399 
400     int *a = nullptr;
401     {
402         ppx::base::MemoryPool<int, 18> mp3;
403         a =  mp3.allocate();
404         *a = 100;
405         //mp3.deallocate(a);
406 
407         int *b =  mp3.allocate();
408         *b = 200;
409         //mp3.deallocate(b);
410 
411         mp3.deallocate(a);
412         mp3.deallocate(b);
413 
414         int *c = mp3.allocate();
415         *c = 300;
416     }
417 
418     getchar();
419     return 0;
420 }

 

posted @ 2022-04-14 09:49  TTTCoder  阅读(94)  评论(0编辑  收藏  举报