多线程内存池

本文探讨了多线程环境下内存池的优化方法,通过对比互斥体与临界区作为锁实现,揭示了不同锁机制对内存操作性能的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如果一个内存池需要线程同步了,估计和默认的内存操作也差不了多远了。现在对内存操作的优化只是在优化线程同步操作上面了。默认的lock和unlock可能实现得过于完美,因而要求更多的cpu周期。如果选择更原子的lock和unlock实现,还是可以加快内存操作的速度的。

多线程内存池在实现上也就是在申请和释放外面包裹了一对加锁和解锁操作而已。

如果我们采用模板编程,就可以实现一个功能强悍的模板类,该模板类有两个参数,单线程内存池和锁。这样的话,可以组合出很多情况。比如说,单线程内存池有对象大小固定和不固定两种实现,锁在Windows下可以用临界区,互斥体,信号量,事件实现。这样最多可以组合出8种不同的实例化。

一般说来互斥体比临界区慢很多,在这里可以进行很好的测试。我实现了临界区和互斥体版本的锁,经过测试发现前者比后者快30多倍。因为互斥体据说是内核对象,而临界区是用户态对象,那么互斥体的使用就需要系统在用户态和内核态之间进行切换,肯定会消耗更多的时间。

互斥体版本代码如下,

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <time.h>
4 #include <windows.h>
5  
6 template <typename T> class MemoryPool
7 {
8 public:
9     MemoryPool(size_t size = EXPANSION_SIZE)
10     {
11         expandTheFreeList(size);
12     }
13     ~MemoryPool();
14     //allocate a T element from the free list.
15     void* alloc(size_t size)
16     {
17         if (next == NULL)
18         {
19             expandTheFreeList();
20         }
21         MemoryPool<T>* head = next;
22         next = head->next;
23         return head;
24     }
25     //return a T element to the free list.
26     void free(void* doomed)
27     {
28         MemoryPool<T>* head = static_cast< MemoryPool<T>* > (doomed);
29         head->next = next;
30         next = head;
31     }
32  
33 private:
34     //next element on the free list.
35     MemoryPool<T>* next;
36     //if the freelist is empty, expand it by this amount.
37     enum {EXPANSION_SIZE = 32};
38     //add free elements to the free list
39     void expandTheFreeList(int howMany = EXPANSION_SIZE);
40 };
41  
42 template <typename T> MemoryPool<T> :: ~MemoryPool()
43 {
44     MemoryPool<T>* nextPtr = NULL;
45     while (nextPtr)
46     {
47         nextPtr = next;
48         next = next->next;
49         delete [] nextPtr;
50     }
51 }
52  
53 template <typename T> void MemoryPool<T> :: expandTheFreeList(inthowMany)
54 {
55     //we must allocate an object enough to contain the next pointer
56     size_t size = sizeof(T) > sizeof(MemoryPool<T>*) ? sizeof(T) :
57                   sizeof(MemoryPool<T>*);
58  
59     MemoryPool<T>* runner = (MemoryPool<T>*) new char[size];
60     next = runner;
61     for (int i = 0; i < howMany; ++i)
62     {
63         runner->next = (MemoryPool<T>*) new char[size];
64         runner = runner->next;
65     }
66     runner->next = NULL;
67 }
68  
69 class ABClock //abstract base class
70 {
71 public:
72     virtual ~ABClock() {}
73     virtual void lock() = 0;
74     virtual void unlock() = 0;
75 };
76  
77 class MutexLock : public ABClock
78 {
79 public:
80     MutexLock()
81     {
82         hMutex = CreateMutex(NULL, FALSE, NULL);
83     }
84     ~MutexLock()
85     {
86         CloseHandle(hMutex);
87     }
88     void lock()
89     {
90         WaitForSingleObject(hMutex, INFINITE);
91     }
92     void unlock()
93     {
94         ReleaseMutex(hMutex);
95     }
96 private:
97     HANDLE hMutex;
98 };
99  
100 template <typename POOLTYPE, typename LOCK>
101 class MTMemoryPool
102 {
103 public:
104     //allocate an element from the freelist.
105     void* alloc(size_t size)
106     {
107         void* mem;
108         theLock.lock();
109         mem = stPool.alloc(size);
110         theLock.unlock();
111         return mem;
112     }
113  
114     //return an element to the freelist
115     void free(void* someElement)
116     {
117         theLock.lock();
118         stPool.free(someElement);
119         theLock.unlock();
120     }
121  
122 private:
123     POOLTYPE stPool;//Single-threaded pool.
124     LOCK theLock;
125 };
126  
127 class Rational
128 {
129 public:
130     Rational(int a = 0, int b = 1) : n(a), d(b) {}
131     void* operator new(size_t size)
132     {
133         return memPool->alloc(size);
134     }
135     void operator delete(void* doomed, size_t size)
136     {
137         memPool->free(doomed);
138     }
139     static void newMemPool()
140     {
141         memPool = new MTMemoryPool< MemoryPool<Rational>, MutexLock>;
142     }
143     static void deleteMemPool()
144     {
145         delete memPool;
146     }
147  
148 private:
149     int n;
150     int d;
151     static MTMemoryPool< MemoryPool<Rational>, MutexLock>* memPool;
152 };
153 MTMemoryPool< MemoryPool<Rational>, MutexLock>* Rational::memPool = NULL;
154  
155 int main()
156 {
157     const int ARRAY_SIZE = 1000;
158     const int LOOP_TIMES = 5000;
159  
160     Rational* array[ARRAY_SIZE];
161     clock_t beg = clock();
162     Rational::newMemPool();
163     for (int i = 0; i < LOOP_TIMES; ++i)
164     {
165         for (int j = 0; j < ARRAY_SIZE; ++j)
166         {
167             array[j] = new Rational(j);
168         }
169         for (int j = 0; j < ARRAY_SIZE; ++j)
170         {
171             delete array[j];
172         }
173     }
174     clock_t end = clock();
175     printf("use %f second(s).\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
176     system("pause");
177     Rational::deleteMemPool();
178  
179     return 0;
180 }

运行结果,

临界区版本代码如下,

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <time.h>
4 #include <windows.h>
5  
6 template <typename T> class MemoryPool
7 {
8 public:
9     MemoryPool(size_t size = EXPANSION_SIZE)
10     {
11         expandTheFreeList(size);
12     }
13     ~MemoryPool();
14     //allocate a T element from the free list.
15     void* alloc(size_t size)
16     {
17         if (next == NULL)
18         {
19             expandTheFreeList();
20         }
21         MemoryPool<T>* head = next;
22         next = head->next;
23         return head;
24     }
25     //return a T element to the free list.
26     void free(void* doomed)
27     {
28         MemoryPool<T>* head = static_cast< MemoryPool<T>* > (doomed);
29         head->next = next;
30         next = head;
31     }
32  
33 private:
34     //next element on the free list.
35     MemoryPool<T>* next;
36     //if the freelist is empty, expand it by this amount.
37     enum {EXPANSION_SIZE = 32};
38     //add free elements to the free list
39     void expandTheFreeList(int howMany = EXPANSION_SIZE);
40 };
41  
42 template <typename T> MemoryPool<T> :: ~MemoryPool()
43 {
44     MemoryPool<T>* nextPtr = NULL;
45     while (nextPtr)
46     {
47         nextPtr = next;
48         next = next->next;
49         delete [] nextPtr;
50     }
51 }
52  
53 template <typename T> void MemoryPool<T> :: expandTheFreeList(inthowMany)
54 {
55     //we must allocate an object enough to contain the next pointer
56     size_t size = sizeof(T) > sizeof(MemoryPool<T>*) ? sizeof(T) :
57                   sizeof(MemoryPool<T>*);
58  
59     MemoryPool<T>* runner = (MemoryPool<T>*) new char[size];
60     next = runner;
61     for (int i = 0; i < howMany; ++i)
62     {
63         runner->next = (MemoryPool<T>*) new char[size];
64         runner = runner->next;
65     }
66     runner->next = NULL;
67 }
68  
69 class ABClock //abstract base class
70 {
71 public:
72     virtual ~ABClock() {}
73     virtual void lock() = 0;
74     virtual void unlock() = 0;
75 };
76  
77 class CriticalSectionLock : public ABClock
78 {
79 public:
80     CriticalSectionLock()
81     {
82         InitializeCriticalSection(&csMyCriticalSection);
83     }
84     ~CriticalSectionLock()
85     {
86         DeleteCriticalSection(&csMyCriticalSection);
87     }
88     void lock()
89     {
90         EnterCriticalSection(&csMyCriticalSection);
91     }
92     void unlock()
93     {
94         LeaveCriticalSection(&csMyCriticalSection);
95     }
96 private:
97     CRITICAL_SECTION csMyCriticalSection;
98 };
99  
100 template <typename POOLTYPE, typename LOCK>
101 class MTMemoryPool
102 {
103 public:
104     //allocate an element from the freelist.
105     void* alloc(size_t size)
106     {
107         void* mem;
108         theLock.lock();
109         mem = stPool.alloc(size);
110         theLock.unlock();
111         return mem;
112     }
113  
114     //return an element to the freelist
115     void free(void* someElement)
116     {
117         theLock.lock();
118         stPool.free(someElement);
119         theLock.unlock();
120     }
121  
122 private:
123     POOLTYPE stPool;//Single-threaded pool.
124     LOCK theLock;
125 };
126  
127 class Rational
128 {
129 public:
130     Rational(int a = 0, int b = 1) : n(a), d(b) {}
131     void* operator new(size_t size)
132     {
133         return memPool->alloc(size);
134     }
135     void operator delete(void* doomed, size_t size)
136     {
137         memPool->free(doomed);
138     }
139     static void newMemPool()
140     {
141         memPool = new MTMemoryPool< MemoryPool<Rational>, CriticalSectionLock>;
142     }
143     static void deleteMemPool()
144     {
145         delete memPool;
146     }
147  
148 private:
149     int n;
150     int d;
151     static MTMemoryPool< MemoryPool<Rational>, CriticalSectionLock>* memPool;
152 };
153 MTMemoryPool< MemoryPool<Rational>, CriticalSectionLock>* Rational::memPool = NULL;
154  
155 int main()
156 {
157     const int ARRAY_SIZE = 1000;
158     const int LOOP_TIMES = 5000;
159  
160     Rational* array[ARRAY_SIZE];
161     clock_t beg = clock();
162     Rational::newMemPool();
163     for (int i = 0; i < LOOP_TIMES; ++i)
164     {
165         for (int j = 0; j < ARRAY_SIZE; ++j)
166         {
167             array[j] = new Rational(j);
168         }
169         for (int j = 0; j < ARRAY_SIZE; ++j)
170         {
171             delete array[j];
172         }
173     }
174     clock_t end = clock();
175     printf("use %f second(s).\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
176     system("pause");
177     Rational::deleteMemPool();
178  
179     return 0;
180 }

运行结果,

两个版本的代码只在线程同步锁的实现上有差别,但是速度却相差了30多倍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值