共享Windows下C++庫之線程池篇

 

上一篇我把創建單個線程的源碼給出來了,當然,線程池的也不能拉下~

 

很多時候,我們需要一組線程來解決問題。當然可以創建一些線程來完成工作,然後關閉掉。當又需要時,重複上述過程即可。然而,無論是客戶端還是服務端,完全沒必要如此,只需要實現創建一組線程,按需分配,不必創建--關閉--創建--關閉…

 

也許我們也能自己寫成符合需求的線程池組件,但是,系統也提供了線程池組件。我認爲就應該重複利用(出於學習的目的另當別論)。在這裏,主要針對XP系統,提供一組C++ wrap過的線程池組件和模仿ATL線程池。當然,使用系統的線程池有一定的限制(設置線程堆棧大小等)。但還是能滿足大部分的需求。

 

首先,來看看系統線程池(據《Windows核心編程》所說,在內部都是用完成端口來管理的)

Windows 線程池中的線程有兩種類型,一種可以用來處理異步I/O, 另一種則不能。前者依賴於IO完成端口,IOCP是一種Windows內核對象,它可以將線程和I/O端口綁定在特定的系統資源上,對帶有完成端口的I/O進行處理是一個複雜的過程。

 

  1. QueueUserWorkItemPool--Windows將創建一個線程池,其中的一個線程將執行 回調函數,函數執行完成後,該線程返回線程池,等待新的任務。當然了,你不能在該線程的回調函數中執行ExitThread等破壞行爲。線程池中的線程數量是動態的,Windows內部的調度算法決定當前線程工作負載的最佳方式。如果要執行長時間的處理工作,需要設置WT_EXECUTELONGFUNCTION。如果該線程不執行異步IO,則設置WT_EXECUTIONDEFAULT即可,如果需要執行異步IO,則應該設置WT_EXECUTEIONIOTHREAD標誌來告訴線程池
  2. BindIOCompletionCallbackPool--服務器應用程序發出某些異步IO請求,當這些請求完成時,需要讓一個線程池準備好來處理已完成的IO請求。BindIoCompletionCallback在內部調用CreateIoCompletionPort,傳遞hDevice和內部完成端口的句柄。調用該函數可以保證至少有一個線程始終在非IO組件中,與設備相關的完成鍵是重疊完成例程的地址。
    這樣,當該設備的IO運行完成時,非IO組件就知道調用哪個函數,以便能夠處理已完成IO請求
  3. RegisterWaitForSingleObjectPool--線程池在等待一個事件,當該事件被激活時,會喚醒一個線程來執行註冊的回調函數。

 

其次,來看如何使用,簡單展示下QueueUserWorkItemPool,其他的則在Example中給出

class A
{
enum { Count = 1000000 };
public:
void DoWork()
{
LONG lVal = 0;
for(DWORD i = 0; i != Count; ++i)
{
InterlockedExchangeAdd(&lVal, i);
}

}

void DoWork(int nNum)
{
LONG lVal = 0;
for(DWORD i = 0; i != nNum; ++i)
{
InterlockedExchangeAdd(&lVal, i);
}
}
};

A a;
QueueUserWorkItemPool::Call(&A::DoWork, &a);
QueueUserWorkItemPool::CallEx(&A::DoWork, &a, nCount);

很簡單,是吧,只需要設置回調函數,CallEx比Call多提供一個額外參數,當然可以是任意類型.

然而,在對於BindIOCompletionCallbackPool的設計時,爲了區分每個不同的回調函數,把自己弄成了模板類,需要提供一個額外的模板參數來進行區分--

BindIOCompletionCallbackPool<1>::CallBindIOCompletionCallbackPool<2>::Call

 

如果你有更好的建議,希望你能提出,大家共同提高。

 

所有的源碼和示例以提供:(需要更改後綴,把.gif改爲.rar,用右鍵下載)

猛擊這裏 猛擊這裏

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章