关闭

“池化技术”漫谈 - 线程池,内存池,连接池……

782人阅读 评论(0) 收藏 举报
分类:
 

“池化技术”漫谈 - 线程池,内存池,连接池……

分类: C++ Win32 5694人阅读 评论(0) 收藏 举报

池化技术 - 简单点来说,就是提前保存大量的资源,以备不时之需,O(∩_∩)O,对于线程,内存,oracle的连接对象等等,这些都是资源,程序中当你创建一个线程或者在堆上申请一块内存时,都涉及到很多系统调用,也是非常消耗CPU的,如果你的程序需要很多类似的工作线程或者需要频繁的申请释放小块内存,如果没有在这方面进行优化,那很有可能这部分代码将会成为影响你整个程序性能的瓶颈。池化技术主要有线程池,内存池,连接池,对象池等等,对象池就是提前创建很多对象,将用过的对象保存起来,等下一次需要这种对象的时候,再拿出来重复使用,连接池比较典型的有oracle的连接池,了解不深。

下面主要谈谈线程池和内存池,因为这两种技术的通用性和实用性也是比较强的,描述语言C++,其实线程池的话用什么实现都可以。

 

先来谈谈线程池技术,线程池的框架早就有先辈给我们想好了,也就不用我们去冥思苦想了,我们要做的就是把先辈的想法发现即可。

其实线程池的原理很简单,类似于操作系统中的缓冲区的概念,它的流程如下:先启动若干数量的线程,并让这些线程都处于睡眠状态,当客户端有一个新请求时,就会唤醒线程池中的某一个睡眠线程,让它来处理客户端的这个请求,当处理完这个请求后,线程又处于睡眠状态。可能你也许会问:为什么要搞得这么麻烦,如果每当客户端有新的请求时,我就创建一个新的线程不就完了?这也许是个不错的方法,因为它能使得你编写代码相对容易一些,但你却忽略了一个重要的问题?性能!尤其是对于服务器程序尤为重要,服务器程序会先初始化很多线程在那里等待,当有客户连接时,就激活其中的一个线程来处理客户请求,对于不支持动态增加的线程池,如果没有等待线程,客户就必学等待,而对于能动态增加线程的线程池,则可以像线程池中新加一个线程。

下面是一个用c++实现的线程池,支持动态增减线程数量:

  1. /* -------------------------------------------------------------------------
  2. //  文件名     :   KThreadPool.h
  3. //  创建者     :   magicTong
  4. //  创建时间    :   2008-10-23 15:02:31
  5. //  功能描述    :   线程池声明
  6. //
  7. //  $Id: $
  8. // -----------------------------------------------------------------------*/
  9. #ifndef __KTHREADPOOL_H__
  10. #define __KTHREADPOOL_H__
  11. // -------------------------------------------------------------------------
  12. #include <windows.h>
  13. #include <list>
  14. using namespace std;
  15. // 线程函数指针定义 
  16. typedef DWORD (WINAPI *PTHREAD_FUNC_EX)(LPVOID lpThreadParameter);
  17. // 线程状态枚举
  18. typedef enum _enumKThreadStatus
  19. {
  20.     THREADRUN,      // 运行
  21.     THREADPAUSE,    // 暂停
  22. }
  23. KThreadStatus;
  24. // -------------------------------------------------------------------------
  25. // 类名       : KThread
  26. // 功能       : 线程类,可动态更换执行函数
  27. // 附注       : 
  28. // -------------------------------------------------------------------------
  29. class KThread
  30. {
  31. public:
  32.     // 构造
  33.     KThread();
  34.     // 析构
  35.     ~KThread();
  36.     // -------------------------------------------------------------------------
  37.     // 函数       : Init
  38.     // 功能       : 初始化函数
  39.     // 返回值  : bool 
  40.     // 附注       : 
  41.     // -------------------------------------------------------------------------
  42.     bool Init();
  43.     // -------------------------------------------------------------------------
  44.     // 函数       : Run
  45.     // 功能       : 运行线程
  46.     // 返回值  : bool 
  47.     // 附注       : 
  48.     // -------------------------------------------------------------------------
  49.     bool Run();
  50.     // -------------------------------------------------------------------------
  51.     // 函数       : Pause
  52.     // 功能       : 暂停线程
  53.     // 返回值  : bool 
  54.     // 附注       : 
  55.     // -------------------------------------------------------------------------
  56.     bool Pause();
  57.     // -------------------------------------------------------------------------
  58.     // 函数       : Join
  59.     // 功能       : 调用Join的线程将阻塞,直到该线程执行完毕
  60.     // 返回值  : void 
  61.     // 附注       : 
  62.     // -------------------------------------------------------------------------
  63.     void Join();
  64.     // -------------------------------------------------------------------------
  65.     // 函数       : SetProc
  66.     // 功能       : 设置线程运行的函数,和要传给线程的参数
  67.     // 返回值  : void 
  68.     // 参数       : PTHREAD_FUNC_EX proc
  69.     // 参数       : void* lpParam
  70.     // 附注       : 
  71.     // -------------------------------------------------------------------------
  72.     void SetProc(PTHREAD_FUNC_EX proc, void* lpParam);
  73. protected:
  74.     KThread(KThread&){}
  75.     // 线程实际运行的函数
  76.     static DWORD WINAPI RealThreadProc(void* lpParam);
  77.     friend class KThreadPool;
  78. protected:
  79.     struct KThreadParam
  80.     {
  81.         PTHREAD_FUNC_EX proc;   // 用户线程函数
  82.         void *lpParam;          // 用户线程参数
  83.         KThread *pThread;       // 线程类对象
  84.     };
  85.     HANDLE              m_hThread;
  86.     DWORD               m_id;
  87.     KThreadParam        m_param;
  88.     KThreadStatus       m_status;
  89.     HANDLE              m_hEvt;
  90.     HANDLE              m_hMtx;
  91. };
  92. // -------------------------------------------------------------------------
  93. // 类名       : KThreadPool
  94. // 功能       : 线程池类声明
  95. // 附注       : 
  96. // -------------------------------------------------------------------------
  97. class KThreadPool
  98. {
  99. public:
  100.     //构造,initNum初始情况线程数量
  101.     KThreadPool(int initNum);
  102.     //析构
  103.     ~KThreadPool();
  104.     // -------------------------------------------------------------------------
  105.     // 函数       : DoWork
  106.     // 功能       : 申请线程进行工作,proc工作函数,lpParam工作函数参数,run是否立即运行,返回线程ID
  107.     // 返回值  : DWORD 
  108.     // 参数       : PTHREAD_FUNC_EX proc
  109.     // 参数       : void *lpParam
  110.     // 参数       : bool run = true
  111.     // 附注       : 
  112.     // -------------------------------------------------------------------------
  113.     DWORD DoWork(PTHREAD_FUNC_EX proc, void *lpParam, bool run = true);
  114.     // -------------------------------------------------------------------------
  115.     // 函数       : Run
  116.     // 功能       : 运行线程,id线程ID
  117.     // 返回值  : bool 
  118.     // 参数       : DWORD id
  119.     // 附注       : 
  120.     // -------------------------------------------------------------------------
  121.     bool Run(DWORD id);
  122.     // -------------------------------------------------------------------------
  123.     // 函数       : Pause
  124.     // 功能       : 暂停运行线程,id线程ID
  125.     // 返回值  : bool 
  126.     // 参数       : DWORD id
  127.     // 附注       : 
  128.     // -------------------------------------------------------------------------
  129.     bool Pause(DWORD id);
  130.     //调整线程池大小为size,返回调整后线程池大小
  131.     unsigned SetSize(unsigned size);
  132. protected:
  133.     list<KThread*> m_lst;
  134. };

实现:

  1. /* -------------------------------------------------------------------------
  2. //  文件名     :   KThreadPool.cpp
  3. //  创建者     :   magicTong
  4. //  创建时间    :   2008-10-23 15:02:22
  5. //  功能描述    :   线程池定义
  6. //
  7. //  $Id: $
  8. // -----------------------------------------------------------------------*/
  9. #include "stdafx.h"
  10. #include "KThreadPool.h"
  11. // -------------------------------------------------------------------------
  12. // -------------------------------------------------------------------------
  13. // KThread类定义开始
  14. // -------------------------------------------------------------------------
  15. KThread::KThread(): m_hThread(NULL), 
  16.                     m_status(THREADPAUSE), 
  17.                     m_hEvt(0), 
  18.                     m_hMtx(0)
  19. {
  20. }
  21. KThread::~KThread()
  22. {
  23.     ::CloseHandle(m_hMtx);
  24.     if (::TerminateThread(m_hThread, -1) == 0)
  25.         return;
  26. }
  27. bool KThread::Init()
  28. {
  29.     m_hThread = ::CreateThread(
  30.                                 0, 
  31.                                 0, 
  32.                                 (PTHREAD_FUNC_EX)(KThread::RealThreadProc),
  33.                                 (void*)&m_param, 
  34.                                 CREATE_SUSPENDED, 
  35.                                 &m_id);
  36.     // 创建线程失败
  37.     if (NULL == m_hThread)
  38.     {
  39.         return false;
  40.     }
  41.     m_param.proc = NULL;
  42.     m_param.lpParam = NULL;
  43.     m_param.pThread = this;
  44.     //自动复位
  45.     m_hEvt = ::CreateEvent(0, FALSE, FALSE, 0);
  46.     if (m_hEvt == 0)
  47.     {
  48.         ::CloseHandle(m_hThread);
  49.         return false;
  50.     }
  51.     m_hMtx = ::CreateMutex(0, 0, 0);
  52.     if (m_hMtx == 0)
  53.     {
  54.         ::CloseHandle(m_hEvt);
  55.         ::CloseHandle(m_hThread);
  56.         return false;
  57.     }
  58.     return true;
  59. }
  60. bool KThread::Run()
  61. {
  62.     ::WaitForSingleObject(m_hMtx, INFINITE);
  63.     if (m_status == THREADPAUSE)
  64.         if (::ResumeThread(m_hThread) == -1)
  65.         {
  66.             ::ReleaseMutex(m_hMtx);
  67.             return false;
  68.         }
  69.     
  70.     m_status = THREADRUN;
  71.     ::ReleaseMutex(m_hMtx);
  72.     return true;
  73. }
  74. bool KThread::Pause()
  75. {
  76.     ::WaitForSingleObject(m_hMtx, INFINITE);
  77.     if (m_status == THREADRUN)
  78.         if (::SuspendThread(m_hThread) == -1)
  79.         {
  80.             ::ReleaseMutex(m_hMtx);
  81.             return false;
  82.         }
  83.     m_status = THREADPAUSE;
  84.     ::ReleaseMutex(m_hMtx);
  85.     return true;
  86. }
  87. void KThread::Join()
  88. {
  89.     ::WaitForSingleObject(m_hEvt, INFINITE);
  90. }
  91. void KThread::SetProc(PTHREAD_FUNC_EX proc, void* lpParam)
  92. {
  93.     ::WaitForSingleObject(m_hMtx, INFINITE);
  94.     m_param.proc = proc;
  95.     m_param.lpParam = lpParam;
  96.     ::ReleaseMutex(m_hMtx);
  97. }
  98. DWORD WINAPI KThread::RealThreadProc(void* lpParam)
  99. {
  100.     PTHREAD_FUNC_EX proc;
  101.     KThreadParam *pp = (KThreadParam*)lpParam;
  102.     while (true)
  103.     {
  104.         proc = pp->proc;
  105.         if (proc)
  106.             (*proc)(pp->lpParam);
  107.         pp->proc = NULL;
  108.         pp->lpParam = NULL;
  109.         pp->pThread->Pause();
  110.         ::SetEvent(pp->pThread->m_hEvt);
  111.     }
  112. }
  113. // -------------------------------------------------------------------------
  114. // KThread类定义结束
  115. // -------------------------------------------------------------------------
  116. // -------------------------------------------------------------------------
  117. // KThreadPool类定义开始
  118. // -------------------------------------------------------------------------
  119. KThreadPool::KThreadPool(int initNum)
  120. {
  121.     KThread *pt;
  122.     for (int i = 0; i < initNum; i++)
  123.     {
  124.         pt = new KThread;
  125.         if (pt->Init())
  126.             m_lst.push_back(pt);
  127.     }
  128. }
  129. KThreadPool::~KThreadPool()
  130. {
  131.     list<KThread*>::iterator itBegin = m_lst.begin();
  132.     list<KThread*>::iterator itEnd = m_lst.end();
  133.     for ( ; itBegin != itEnd; itBegin++)
  134.     {
  135.         delete (*itBegin);
  136.     }
  137. }
  138. DWORD KThreadPool::DoWork(LPTHREAD_START_ROUTINE proc, void *lpParam, bool run)
  139. {
  140.     list<KThread*>::iterator itBegin = m_lst.begin();
  141.     list<KThread*>::iterator itEnd = m_lst.end();
  142.     for (; itBegin != itEnd; itBegin++)
  143.     {
  144.         if ((*itBegin)->m_param.proc == NULL && (*itBegin)->m_status == THREADPAUSE)
  145.         {
  146.             (*itBegin)->SetProc(proc, lpParam);
  147.             
  148.             // 立即运行
  149.             if (run)
  150.                 (*itBegin)->Run();
  151.             return (*itBegin)->m_id;
  152.         }
  153.     }
  154.     // 没有空闲线程,新建一个新的线程,加入链表
  155.     KThread *pt = new KThread;
  156.     if (pt->Init())
  157.         m_lst.push_back(pt);
  158.     pt->SetProc(proc, lpParam);
  159.     if (run)
  160.         pt->Run();
  161.     return pt->m_id;
  162. }
  163. bool KThreadPool::Run(DWORD id)
  164. {
  165.     list<KThread*>::iterator itBegin = m_lst.begin();
  166.     list<KThread*>::iterator itEnd = m_lst.end();
  167.     for (; itBegin != itEnd; itBegin++)
  168.     {
  169.         if ((*itBegin)->m_id == id)
  170.         return ((*itBegin)->Run());
  171.     }
  172.     return false;
  173. }
  174. bool KThreadPool::Pause(DWORD id)
  175. {
  176.     list<KThread*>::iterator itBegin = m_lst.begin();
  177.     list<KThread*>::iterator itEnd = m_lst.end();
  178.     for (; itBegin != itEnd; itBegin++)
  179.     {
  180.         if ((*itBegin)->m_id == id)
  181.             return ((*itBegin)->Pause());
  182.     }
  183.     
  184.     return false;
  185. }
  186. // -------------------------------------------------------------------------
  187. // 函数       : KThreadPool::SetSize
  188. // 功能       : 修改线程池的大小
  189. // 返回值  : unsigned 
  190. // 参数       : unsigned size
  191. // 附注       : 如果小缩小线程池大小,谨慎使用
  192. // -------------------------------------------------------------------------
  193. unsigned KThreadPool::SetSize(unsigned size)
  194. {
  195.     unsigned nowsize = m_lst.size();
  196.     if (nowsize <= size)
  197.     {
  198.         KThread *pt;
  199.         unsigned inc = size - nowsize;
  200.         for (unsigned i = 0; i < inc; i++)
  201.         {
  202.             pt = new KThread;
  203.             if (pt->Init())
  204.             {
  205.                 m_lst.push_back(pt);
  206.             }
  207.         }
  208.         return size;
  209.     }
  210.     else
  211.     {
  212.         unsigned dec = nowsize - size;
  213.         list<KThread*>::iterator it = m_lst.begin();
  214.         list<KThread*>::iterator ite = m_lst.end();
  215.         list<KThread*>::iterator itemp;
  216.         unsigned i = 0;
  217.         for (; it != ite && i < dec;)
  218.         {
  219.             if ((*it)->m_status == THREADPAUSE)
  220.             {
  221.                 itemp = it++;
  222.                 delete ((*itemp));
  223.                 m_lst.erase(itemp);
  224.                 i++;
  225.                 continue;
  226.             }
  227.             it++;
  228.         }
  229.         ::Sleep(100 * i);
  230.         return m_lst.size();
  231.     }
  232. }
  233. // -------------------------------------------------------------------------
  234. // KThreadPool类定义结束
  235. // -------------------------------------------------------------------------

使用:

要定义一个线程函数,然后再将该函数和线程数量设置到内存池中,测试代码如下:

  1. DWORD WINAPI threadFunc(LPVOID lpThreadParam);
  2. void CKThreadPoolExDlg::OnBtnCreate() 
  3. {
  4.     static i = 0;
  5.     if (!m_pThreadPool)
  6.     {
  7.         m_pThreadPool = new KThreadPool(1);
  8.     }
  9.     
  10.     m_pThreadPool->DoWork(threadFunc, thistrue);
  11.     i++;
  12.     if (i == 4)
  13.     {
  14.         m_pThreadPool->SetSize(10);
  15.     }
  16. }
  17. void CKThreadPoolExDlg::DoSomething()
  18. {
  19.     //MessageBox("O(∩_∩)O哈哈~");
  20.     while (true)
  21.     {
  22.         ::EnterCriticalSection(&m_cs);
  23.         DWORD id = GetCurrentThreadId();
  24.         CString cstr;
  25.         cstr.Format("线程 %d 正在运行...", id);
  26.         m_listInfo.InsertItem(m_listInfo.GetItemCount(), cstr);
  27.         ::LeaveCriticalSection(&m_cs);
  28.         ::Sleep(400);
  29.     }
  30. }
  31. DWORD WINAPI threadFunc(LPVOID lpThreadParam)
  32. {
  33.     CKThreadPoolExDlg *pdlg = (CKThreadPoolExDlg *)lpThreadParam;
  34.     pdlg->DoSomething();
  35.     return 0;
  36. }

代码的详细注释我就不写了,想弄懂原理的还是好好研究下再使用,我不保证里面没有BUG。

 

再来看看内存池的原理,我下面的参考资料里面有几篇文章讲得不错,想了解原理的可以去看看。

如何更好的管理在应用程序中内存的使用,同时提高内存使用的效率,这是值得每一个开发人员深思的问题。内存池(Memory pool)提供了一种比较可行的解决方案。首先是创建内存池。这个过程的主要任务是预先分配足够大的内存,形成一个初步的“内存池”。分配内存,也就是用户请求内存时,会返回内存池中一块空闲的内存,并将其标志置为已使用,当然具体细节和方法有很多。释放内存时,不是真正地调用free或是delete的过程,而是把内存放回内存池的过程。在把内存放入内存池的同时,要把标志位置为空闲。最后在应用程序结束时,要把内存池销毁。这里主要做的工作就是把内存池中的每一块内存释放。

使用内存池的好处:

1、减少了内存碎片的产生。这个可以从创建内存池的过程中看出。我们在创建内存池时,分配的都是一块块比较整的内存块,这样可以减少内存碎片的产生。

2、提高了内存的使用效率。这个可以从分配内存和释放内存的过程中看出。每次的分配与释放并不是去调用系统提供的函数或是操作符去操作实际的内存,而是在复用内存池中的内存。

缺点就是很有可能会造成内存的浪费,原因也很明显,开始分配了一大块内存,不是全部都用得到的。

针对内存池,这里有两个实现,头一个很简单,用到了STL的队列来管理内存池指针,而且如果分配的内存没有显示的归还给内存池的话,即使内存池销毁的时候,这块内存也不会被销毁,就会有内存泄露,当然这个程序还可以改进,另外一个程序是根据《C++应用程序性能优化》中提到的一种方法来实现的,程序见下面:

简单实现(还有很大的改进余地):

  1. /* -------------------------------------------------------------------------
  2. //  文件名     :   MemPool.h
  3. //  创建者     :   magicTong
  4. //  创建时间    :   2008-10-24 17:50:00
  5. //  功能描述    :  一个简单的内存池实现
  6. //
  7. //  $Id: $
  8. // -----------------------------------------------------------------------*/
  9. #ifndef __MEMPOOL_H__
  10. #define __MEMPOOL_H__
  11. // -------------------------------------------------------------------------
  12. #include <queue>
  13. #define  MemoryBlockSize    1024
  14. #define  MemoryBlockNum     20
  15. class KMemPool
  16. {
  17. public:
  18.     // 构造
  19.     explicit KMemPool(int a_memoryBlockNum = MemoryBlockNum, 
  20.                         int a_memoryBlockSize = MemoryBlockSize);
  21.     // 析构
  22.     virtual ~KMemPool();
  23.     // 两个主要的操作
  24.     int NewMemBuf(char*& a_recvBuff);
  25.     int DelMemBuf(char* a_recvBuff);
  26. private:
  27.     void _initMemPool(int a_memoryBlockNum, int a_memoryBlockSize);
  28.     std::queue<char*> m_memPool;
  29. };
  30. // -------------------------------------------------------------------------
  31. // $Log: $
  32. #endif /* __MEMPOOL_H__ */

实现:

  1. /* -------------------------------------------------------------------------
  2. //  文件名     :   MemPool.cpp
  3. //  创建者     :   magicTong
  4. //  创建时间    :   2008-10-24 17:50:19
  5. //  功能描述    :   简单内存池实现
  6. //
  7. //  $Id: $
  8. // -----------------------------------------------------------------------*/
  9. #include "stdafx.h"
  10. #include "MemPool.h"
  11. // -------------------------------------------------------------------------
  12. // 构造
  13. KMemPool::KMemPool(int a_memoryBlockNum /* = MemoryBlockNum */
  14.                    int a_memoryBlockSize /* = MemoryBlockSize */)
  15. {
  16.     _initMemPool(a_memoryBlockNum, a_memoryBlockSize);
  17. }
  18. // 析构
  19. KMemPool::~KMemPool()
  20. {
  21.     char* l_tempBuff = NULL;
  22.     while(!m_memPool.empty())
  23.     {
  24.         l_tempBuff = m_memPool.front();
  25.         m_memPool.pop();
  26.         if(l_tempBuff )
  27.         {
  28.             // 回收
  29.             delete[] l_tempBuff;
  30.             l_tempBuff = NULL;
  31.         }
  32.     }
  33. }
  34. // -------------------------------------------------------------------------
  35. // 函数       : KMemPool::_initMemPool
  36. // 功能       : 
  37. // 返回值  : void 
  38. // 参数       : int a_memoryBlockNum
  39. // 参数       : int a_memoryBlockSize
  40. // 附注       : 
  41. // -------------------------------------------------------------------------
  42. void KMemPool::_initMemPool(int a_memoryBlockNum, int a_memoryBlockSize)
  43. {
  44.     for(int i = 0; i < a_memoryBlockNum; ++i)
  45.     {
  46.         char* l_tempBuff = new char[a_memoryBlockSize];
  47.         if(l_tempBuff == NULL)
  48.             continue;
  49.         m_memPool.push(l_tempBuff);
  50.     }
  51.     
  52. }
  53. // -------------------------------------------------------------------------
  54. // 函数       : KMemPool::NewMemBuf
  55. // 功能       : 申请一块内存,如果内存池空了,这个时候应该再像系统申请,并且在
  56. //            类初始化的时候,加一个增量的变量,也可以提供这样的接口,这里为
  57. //            了简单就没有这么做了,只是为了说明问题而已。
  58. // 返回值  : int 
  59. // 参数       : char*& a_memoryBuff
  60. // 附注       : 如果成功返回0,如果失败返回-1
  61. // -------------------------------------------------------------------------
  62. int KMemPool::NewMemBuf(char*& a_memoryBuff)
  63. {
  64.     // 如果内存池已空,这个时候正确的做法应该是
  65.     // 重新申请大块内存
  66.     if (m_memPool.empty())
  67.     {
  68.         _initMemPool(MemoryBlockNum, MemoryBlockSize);
  69.     }
  70.     a_memoryBuff = m_memPool.front();
  71.     m_memPool.pop();
  72.     if(a_memoryBuff == NULL)
  73.         return -1;
  74.     return 0;
  75. }
  76. // -------------------------------------------------------------------------
  77. // 函数       : KMemPool::DelMemBuf
  78. // 功能       : 回收内存,将其放回队列中
  79. // 返回值  : int 
  80. // 参数       : char* a_memoryBuff
  81. // 附注       : 
  82. // -------------------------------------------------------------------------
  83. int KMemPool::DelMemBuf(char* a_memoryBuff)
  84. {
  85.     m_memPool.push(a_memoryBuff);
  86.     return 0;
  87. }
  88. // -------------------------------------------------------------------------
  89. // $Log: $

根据《C++应用程序性能优化》实现代码如下:

  1. /* -------------------------------------------------------------------------
  2. //  文件名     :   MemPoolEx.h
  3. //  创建者     :   magicTong
  4. //  创建时间    :   2008-10-24 17:49:33
  5. //  功能描述    :   
  6. //
  7. //  $Id: $
  8. // -----------------------------------------------------------------------*/
  9. #ifndef __MEMPOOLEX_H__
  10. #define __MEMPOOLEX_H__
  11. // -------------------------------------------------------------------------
  12. #include <Windows.h>
  13. #define MEMPOOL_ALIGNMENT 4
  14. class KMemBlock  
  15. {
  16. public:
  17.     KMemBlock(USHORT nTypes = 1, USHORT nUnitSize = 0);    
  18.     virtual ~KMemBlock();
  19.     
  20.     void  operator delete(void *p, size_t);
  21.     void * operator new (size_tUSHORT nTypes, USHORT nUnitSize);    
  22.     
  23. public:
  24.     USHORT          nSize;              // 内存块的大小  每个小块所占内存*小块个数
  25.     USHORT          nFree;              // 空闲块数
  26.     USHORT          nFirst;             // 第一个空闲块
  27.     //USHORT          nDummyAlign1;        
  28.     KMemBlock       *pNext;             // 下一个Block
  29.     char            aData[1];           // 数据的初始位置
  30. };
  31. class KMemPoolEx  
  32. {
  33. public:
  34.     KMemPoolEx(USHORT uUnitSize, USHORT uInitSize, USHORT uGrowSize);
  35.     virtual ~KMemPoolEx();
  36.     
  37.     void* Alloc();
  38.     void Free(void* pFree);
  39.     
  40. private:
  41.     void _FreeMemeoryBlock(KMemBlock* pMyBlock);
  42.     
  43.     KMemBlock*      pBlock;         // 第一个block的指针 
  44.     USHORT          nUnitSize;      // 每个小内存块的字节数
  45.     USHORT          nInitSize;      // 初始的Block的内存块数目
  46.     USHORT          nGrowSize;      // 增加的Block的内存块数目
  47. };
  48. // -------------------------------------------------------------------------
  49. // $Log: $
  50. #endif /* __MEMPOOLEX_H__ */

实现部分:

  1. /* -------------------------------------------------------------------------
  2. //  文件名     :   MemPoolEx.cpp
  3. //  创建者     :   magicTong
  4. //  创建时间    :   2008-10-24 17:49:45
  5. //  功能描述    :   
  6. //
  7. //  $Id: $
  8. // -----------------------------------------------------------------------*/
  9. #include "stdafx.h" 
  10. #include "MemPoolEx.h" 
  11. // ------------------------------------------------------------------------- 
  12. // 构造 
  13. KMemBlock::KMemBlock (USHORT nTypes, USHORT nUnitSize)
  14. {
  15.     nFree = nTypes - 1;
  16.     pNext = NULL;
  17.     nSize = nTypes * nUnitSize;
  18.     nFirst = 1;
  19.     char* pData = aData;
  20.     for(USHORT i = 1; i < nTypes; i++)
  21.     {
  22.         *(USHORT *)pData = i;
  23.         pData += nUnitSize;
  24.     }
  25. }
  26. // 析构 
  27. KMemBlock::~KMemBlock()
  28. {
  29. }
  30. // ------------------------------------------------------------------------- 
  31. // 函数       : KMemBlock::operator new 
  32. // 功能       :  
  33. // 返回值  : void *  
  34. // 参数       : size_t 
  35. // 参数       : USHORT nTypes 
  36. // 参数       : USHORT nUnitSize 
  37. // 附注       :  
  38. // ------------------------------------------------------------------------- 
  39. void * KMemBlock::operator new(size_tUSHORT nTypes, USHORT nUnitSize)
  40. {
  41.     return ::operator new (sizeof(KMemBlock) + nTypes * nUnitSize);
  42. }
  43. // ------------------------------------------------------------------------- 
  44. // 函数       : KMemBlock::operator delete 
  45. // 功能       :  
  46. // 返回值  : void   
  47. // 参数       : void *p 
  48. // 参数       : size_t 
  49. // 附注       :  
  50. // ------------------------------------------------------------------------- 
  51. void  KMemBlock::operator delete(void *p, size_t)
  52. {
  53.     ::operator delete (p);
  54. }
  55. // ------------------------------------------------------------------------- 
  56. // 线程池定义 
  57. // ------------------------------------------------------------------------- 
  58. // 构造 
  59. // _uUnitSize 每个小内存块的字节数 
  60. // _uInitSize 是初始的Block的内存块数目 
  61. // _uGrowSize 增加的Block的内存块数目 
  62. KMemPoolEx::KMemPoolEx(USHORT _uUnitSize, USHORT _uInitSize, USHORT _uGrowSize)
  63. {
  64.     pBlock = NULL;
  65.     nInitSize = _uInitSize;
  66.     nGrowSize = _uGrowSize;
  67.     
  68.     if(_uUnitSize <= 2)
  69.         nUnitSize = 2;
  70.     else if(_uUnitSize > 2 && _uUnitSize <= 4)
  71.         nUnitSize = 4;
  72.     else 
  73.     {
  74.         if(_uUnitSize % MEMPOOL_ALIGNMENT == 0)
  75.             nUnitSize = _uUnitSize;
  76.         else
  77.             nUnitSize = (_uUnitSize / MEMPOOL_ALIGNMENT + 1) * MEMPOOL_ALIGNMENT;
  78.     }
  79. }
  80. // 析构 
  81. KMemPoolEx::~KMemPoolEx()
  82. {
  83.     KMemBlock* pMyBlock = pBlock;
  84.     if(pBlock)
  85.         _FreeMemeoryBlock(pMyBlock);
  86. }
  87. // ------------------------------------------------------------------------- 
  88. // 函数       : KMemPool::_FreeMemeoryBlock 
  89. // 功能       : 递归释放内存 
  90. // 返回值  : void  
  91. // 参数       : KMemBlock *pMyBlock 
  92. // 附注       : 其实这个地方没必要使用递归,迭代实现很容易 
  93. // ------------------------------------------------------------------------- 
  94. void KMemPoolEx::_FreeMemeoryBlock(KMemBlock *pMyBlock)
  95. {
  96.     if(pMyBlock->pNext)
  97.         _FreeMemeoryBlock(pMyBlock->pNext);
  98.     delete pMyBlock;
  99. }
  100. // ------------------------------------------------------------------------- 
  101. // 函数       : KMemPoolEx::Alloc 
  102. // 功能       : 申请内存 
  103. // 返回值  : void*  
  104. // 附注       :  
  105. // ------------------------------------------------------------------------- 
  106. void* KMemPoolEx::Alloc()
  107. {
  108.     if(!pBlock)
  109.     {
  110.         // 如果是第一次申请 
  111.         pBlock = new (nInitSize, nUnitSize) KMemBlock(nInitSize, nUnitSize);
  112.         return pBlock->aData;
  113.     }
  114.     // 如果不是第一次申请 
  115.     KMemBlock *pMyBlock = pBlock;
  116.     while(pMyBlock && !pMyBlock->nFree)
  117.         pMyBlock = pMyBlock->pNext;
  118.     //接下来的两种情况:1.找到有空闲块的block 2.找不到 
  119.     void *retval;
  120.     // 找到了空闲块 
  121.     if(pMyBlock)
  122.     {
  123.         pMyBlock->nFree--;
  124.         retval = pMyBlock->aData + nUnitSize * pMyBlock->nFirst;
  125.         pMyBlock->nFirst = *((USHORT*)retval);
  126.         return retval;
  127.     }
  128.     // 没有找到空闲块,要重新申请 
  129.     else
  130.     {
  131.         if(!nGrowSize)
  132.             return NULL;
  133.         KMemBlock* newBlock = new (nGrowSize, nUnitSize) KMemBlock(nGrowSize, nUnitSize);
  134.         if(!newBlock)
  135.             return NULL;
  136.         newBlock->pNext = pBlock;
  137.         pBlock = newBlock;
  138.         return (void*)(newBlock->aData);
  139.     }
  140.     
  141.     return NULL;
  142. }
  143. // ------------------------------------------------------------------------- 
  144. // 函数       : KMemPoolEx::Free 
  145. // 功能       : 释放内存 
  146. // 返回值  : void  
  147. // 参数       : void* pFree 
  148. // 附注       : 释放内存时,并不真正的归还给堆,而且是回收到内存池中 
  149. // ------------------------------------------------------------------------- 
  150. void KMemPoolEx::Free(void* pFree)
  151. {
  152.     KMemBlock* pMyBlock = pBlock;
  153.     KMemBlock* pPreBlock = NULL;    //pMyBlock指向Block的前一个Block,用于设置pNext 
  154.     // 如果要求释放的内存并不是内存池里面的内存,则直接返回,不予释放 
  155.     while((ULONG)pFree < (ULONG)pMyBlock->aData || (ULONG)pFree > (ULONG)(pMyBlock->aData + pMyBlock->nSize))
  156.     {
  157.         pPreBlock = pMyBlock;
  158.         pMyBlock = pMyBlock->pNext;
  159.         if(!pMyBlock)
  160.             return;
  161.     }
  162.     // 是内存池里面分配出去的,回收到内存池,并不真正归还给堆 
  163.     if(pMyBlock)
  164.     {
  165.         pMyBlock->nFree++;
  166.         *((USHORT*)pFree) = pMyBlock->nFirst;
  167.         pMyBlock->nFirst = (USHORT)(((ULONG)pFree - (ULONG)pMyBlock->aData) / nUnitSize);
  168.         
  169.         if(pMyBlock->nFree * nUnitSize == pMyBlock->nSize)   //如果全是自由块 
  170.         {
  171.             if(!pMyBlock->pNext)  //如果这是最后一个block,则将其释放 
  172.             {
  173.                 delete pMyBlock;  //释放 
  174.                 if(pPreBlock)
  175.                     pPreBlock->pNext = NULL;  //设置上一块的pNext指向NULL 
  176.                 else
  177.                     pBlock = NULL;
  178.             }
  179.                 
  180.         }
  181.     }
  182. }
  183. // ------------------------------------------------------------------------- 
  184. // $Log: $

数据库连接池是因为,初始化一个数据库连接是非常消耗系统资源的,因此就在程序开始阶段进行数据库的批量连接,然后把这些连接保存下来,等到要使用的时候才拿出来使用,使用完了再放入连接池中。了解不深就不多说了。

 

参考资料:

CSDN博客:许式伟 著 内存池(MemPool)技术详解 http://blog.csdn.net/xushiweizh/archive/2006/11/22/1402967.aspx

IBM技术文档:内存池 http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html?ca=drs-cn

Java中数据库连接池原理机制讲解:http://www.68design.net/Development/JSP/20703-1.html

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:4622341次
    • 积分:39611
    • 等级:
    • 排名:第98名
    • 原创:22篇
    • 转载:1920篇
    • 译文:0篇
    • 评论:503条
    最新评论