C++線程池的代碼,非常實用

  1. #ifndef _ThreadPool_H_
  2. #define _ThreadPool_H_
  3. #pragma warning(disable: 4530)
  4. #pragma warning(disable: 4786)
  5. #include <cassert>
  6. #include <vector>
  7. #include <queue>
  8. #include <windows.h>
  9. using namespace std;
  10. class ThreadJob  //工作基類
  11. {
  12. public:
  13.   //供線程池調用的虛函數
  14.   virtual void DoJob(void *pPara) = 0;
  15. };
  16. class ThreadPool
  17. {
  18. public:
  19.   //dwNum 線程池規模
  20.   ThreadPool(DWORD dwNum = 4) : _lThreadNum(0), _lRunningNum(0) 
  21.   {
  22.     InitializeCriticalSection(&_csThreadVector);
  23.     InitializeCriticalSection(&_csWorkQueue);
  24.     _EventComplete = CreateEvent(0, falsefalse, NULL);
  25.     _EventEnd = CreateEvent(0, truefalse, NULL);
  26.     _SemaphoreCall = CreateSemaphore(0, 0,  0x7FFFFFFF, NULL);
  27.     _SemaphoreDel =  CreateSemaphore(0, 0,  0x7FFFFFFF, NULL);
  28.     assert(_SemaphoreCall != INVALID_HANDLE_VALUE);
  29.     assert(_EventComplete != INVALID_HANDLE_VALUE);
  30.     assert(_EventEnd != INVALID_HANDLE_VALUE);
  31.     assert(_SemaphoreDel != INVALID_HANDLE_VALUE);
  32.     AdjustSize(dwNum <= 0 ? 4 : dwNum);
  33.   }
  34.   ~ThreadPool()
  35.   {
  36.     DeleteCriticalSection(&_csWorkQueue);
  37.     CloseHandle(_EventEnd);
  38.     CloseHandle(_EventComplete);
  39.     CloseHandle(_SemaphoreCall);
  40.     CloseHandle(_SemaphoreDel);
  41.     vector<ThreadItem*>::iterator iter;
  42.     for(iter = _ThreadVector.begin(); iter != _ThreadVector.end(); iter++)
  43.     {
  44.       if(*iter)
  45.         delete *iter;
  46.     }
  47.     DeleteCriticalSection(&_csThreadVector);
  48.   }
  49.   //調整線程池規模
  50.   int AdjustSize(int iNum)
  51.   {
  52.     if(iNum > 0)
  53.     {
  54.       ThreadItem *pNew;
  55.       EnterCriticalSection(&_csThreadVector);
  56.       for(int _i=0; _i<iNum; _i++)
  57.       {
  58.         _ThreadVector.push_back(pNew = new ThreadItem(this)); 
  59.         assert(pNew);
  60.         pNew->_Handle = CreateThread(NULL, 0, DefaultJobProc, pNew, 0, NULL);
  61.         // set priority
  62.         SetThreadPriority(pNew->_Handle, THREAD_PRIORITY_BELOW_NORMAL);
  63.         assert(pNew->_Handle);
  64.       }
  65.       LeaveCriticalSection(&_csThreadVector);
  66.     }
  67.     else
  68.     {
  69.       iNum *= -1;
  70.       ReleaseSemaphore(_SemaphoreDel,  iNum > _lThreadNum ? _lThreadNum : iNum, NULL);
  71.     }
  72.     return (int)_lThreadNum;
  73.   }
  74.   //調用線程池
  75.   void Call(void (*pFunc)(void  *), void *pPara = NULL)
  76.   {
  77.     assert(pFunc);
  78.     EnterCriticalSection(&_csWorkQueue);
  79.     _JobQueue.push(new JobItem(pFunc, pPara));
  80.     LeaveCriticalSection(&_csWorkQueue);
  81.     ReleaseSemaphore(_SemaphoreCall, 1, NULL);
  82.   }
  83.   //調用線程池
  84.   inline void Call(ThreadJob * p, void *pPara = NULL)
  85.   {
  86.     Call(CallProc, new CallProcPara(p, pPara));
  87.   }
  88.   //結束線程池, 並同步等待
  89.   bool EndAndWait(DWORD dwWaitTime = INFINITE)
  90.   {
  91.     SetEvent(_EventEnd);
  92.     return WaitForSingleObject(_EventComplete, dwWaitTime) == WAIT_OBJECT_0;
  93.   }
  94.   //結束線程池
  95.   inline void End()
  96.   {
  97.     SetEvent(_EventEnd);
  98.   }
  99.   inline DWORD Size()
  100.   {
  101.     return (DWORD)_lThreadNum;
  102.   }
  103.   inline DWORD GetRunningSize()
  104.   {
  105.     return (DWORD)_lRunningNum;
  106.   }
  107.   bool IsRunning()
  108.   {
  109.     return _lRunningNum > 0;
  110.   }
  111. protected:
  112.   //工作線程
  113.   static DWORD WINAPI DefaultJobProc(LPVOID lpParameter = NULL)
  114.   {
  115.     ThreadItem *pThread = static_cast<ThreadItem*>(lpParameter);
  116.     assert(pThread);
  117.     ThreadPool *pThreadPoolObj = pThread->_pThis;
  118.     assert(pThreadPoolObj);
  119.     InterlockedIncrement(&pThreadPoolObj->_lThreadNum);
  120.     HANDLE hWaitHandle[3];
  121.     hWaitHandle[0] = pThreadPoolObj->_SemaphoreCall;
  122.     hWaitHandle[1] = pThreadPoolObj->_SemaphoreDel;
  123.     hWaitHandle[2] = pThreadPoolObj->_EventEnd;
  124.     JobItem *pJob;
  125.     bool fHasJob;
  126.     for(;;)
  127.     {
  128.       DWORD wr = WaitForMultipleObjects(3, hWaitHandle, false, INFINITE);
  129.       //響應刪除線程信號
  130.       if(wr == WAIT_OBJECT_0 + 1)  
  131.         break;
  132.       //從隊列裏取得用戶作業
  133.       EnterCriticalSection(&pThreadPoolObj->_csWorkQueue);
  134.       if(fHasJob = !pThreadPoolObj->_JobQueue.empty())
  135.       {
  136.         pJob = pThreadPoolObj->_JobQueue.front();
  137.         pThreadPoolObj->_JobQueue.pop();
  138.         assert(pJob);
  139.       }
  140.       LeaveCriticalSection(&pThreadPoolObj->_csWorkQueue);
  141.       //受到結束線程信號 確定是否結束線程(結束線程信號 && 是否還有工作)
  142.       if(wr == WAIT_OBJECT_0 + 2 && !fHasJob)  
  143.         break;
  144.       if(fHasJob && pJob)
  145.       {
  146.         InterlockedIncrement(&pThreadPoolObj->_lRunningNum);
  147.         pThread->_dwLastBeginTime = GetTickCount();
  148.         pThread->_dwCount++;
  149.         pThread->_fIsRunning = true;
  150.         pJob->_pFunc(pJob->_pPara); //運行用戶作業
  151.         delete pJob; 
  152.         pThread->_fIsRunning = false;
  153.         InterlockedDecrement(&pThreadPoolObj->_lRunningNum);
  154.       }
  155.     }
  156.     //刪除自身結構
  157.     EnterCriticalSection(&pThreadPoolObj->_csThreadVector);
  158.     pThreadPoolObj->_ThreadVector.erase(find(pThreadPoolObj->_ThreadVector.begin(), pThreadPoolObj->_ThreadVector.end(), pThread));
  159.     LeaveCriticalSection(&pThreadPoolObj->_csThreadVector);
  160.     delete pThread;
  161.     InterlockedDecrement(&pThreadPoolObj->_lThreadNum);
  162.     if(!pThreadPoolObj->_lThreadNum)  //所有線程結束
  163.       SetEvent(pThreadPoolObj->_EventComplete);
  164.     return 0;
  165.   }
  166.   //調用用戶對象虛函數
  167.   static void CallProc(void *pPara) 
  168.   {
  169.     CallProcPara *cp = static_cast<CallProcPara *>(pPara);
  170.     assert(cp);
  171.     if(cp)
  172.     {
  173.       cp->_pObj->DoJob(cp->_pPara);
  174.       delete cp;
  175.     }
  176.   }
  177.   //用戶對象結構
  178.   struct CallProcPara  
  179.   {
  180.     ThreadJob* _pObj;//用戶對象 
  181.     void *_pPara;//用戶參數
  182.     CallProcPara(ThreadJob* p, void *pPara) : _pObj(p), _pPara(pPara) { };
  183.   };
  184.   //用戶函數結構
  185.   struct JobItem 
  186.   {
  187.     void (*_pFunc)(void  *);//函數
  188.     void *_pPara; //參數
  189.     JobItem(void (*pFunc)(void  *) = NULL, void *pPara = NULL) : _pFunc(pFunc), _pPara(pPara) { };
  190.   };
  191.   //線程池中的線程結構
  192.   struct ThreadItem
  193.   {
  194.     HANDLE _Handle; //線程句柄
  195.     ThreadPool *_pThis;  //線程池的指針
  196.     DWORD _dwLastBeginTime; //最後一次運行開始時間
  197.     DWORD _dwCount; //運行次數
  198.     bool _fIsRunning;
  199.     ThreadItem(ThreadPool *pthis) : _pThis(pthis), _Handle(NULL), _dwLastBeginTime(0), _dwCount(0), _fIsRunning(false) { };
  200.     ~ThreadItem()
  201.     {
  202.       if(_Handle)
  203.       {
  204.         CloseHandle(_Handle);
  205.         _Handle = NULL;
  206.       }
  207.     }
  208.   };
  209.   std::queue<JobItem *> _JobQueue;  //工作隊列
  210.   std::vector<ThreadItem *>  _ThreadVector; //線程數據
  211.   CRITICAL_SECTION _csThreadVector, _csWorkQueue; //工作隊列臨界, 線程數據臨界
  212.   HANDLE _EventEnd, _EventComplete, _SemaphoreCall, _SemaphoreDel;//結束通知, 完成事件, 工作信號, 刪除線程信號
  213.   long _lThreadNum, _lRunningNum; //線程數, 運行的線程數
  214. };
  215. #endif //_ThreadPool_H_

基本上是拿來就用了,對WIN32 API不熟,但對線程池的邏輯還是比較熟的,認爲這個線程池寫得很清晰,我拿來用在一個多線程下載的模塊中。很實用的東東。
調用方法
void threadfunc(void *p)
{
     YourClass* yourObject = (YourClass*)    p;

 //...
}
 ThreadPool tp;
 for(i=0; i<100; i++)
  tp.Call(threadfunc);

ThreadPool tp(20);//20爲初始線程池規模

 tp.Call(threadfunc, lpPara);
     

使用時注意幾點:
1. ThreadJob  沒什麼用,直接寫線程函數吧。 
2. 線程函數(threadfunc)的入口參數void* 可以轉成自定義的類型對象,這個對象可以記錄下線程運行中的數據,並設置線程當前狀態,以此與線程進行交互。
3. 線程池有一個EndAndWait函數,用於讓線程池中所有計算正常結束。有時線程池中的一個線程可能要運行很長時間,怎麼辦?可以通過線程函數threadfunc的入口參數對象來處理,比如:
class YourClass {
  int cmd; // cmd = 1是上線程停止計算,正常退出。
};
threadfunc(void* p) {
  YourClass* yourObject = (YourClass*)p;
  while (true) {
    // do some calculation
    if (yourClass->cmd == 1)
      break;
  }
}
在主線程中設置yourClass->cmd = 1,該線程就會自然結束。
很簡潔通用的線程池實現。

發佈了49 篇原創文章 · 獲贊 27 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章