線程池原理及創(chuàng)建(C++實(shí)現(xiàn))_第1頁
線程池原理及創(chuàng)建(C++實(shí)現(xiàn))_第2頁
線程池原理及創(chuàng)建(C++實(shí)現(xiàn))_第3頁
線程池原理及創(chuàng)建(C++實(shí)現(xiàn))_第4頁
線程池原理及創(chuàng)建(C++實(shí)現(xiàn))_第5頁
已閱讀5頁,還剩25頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、線程池原理及創(chuàng)建(C+實(shí)現(xiàn))時(shí)間:2010 02 2514:40:43來源:網(wǎng)絡(luò)作者未知 點(diǎn)擊:2963次 本文給出了一個(gè)通用的線程池框架,該框架將與線程執(zhí)行相關(guān)的任務(wù)進(jìn)行了高層次的抽象,使之 與具體的執(zhí)行任務(wù)無關(guān)。另外該線程池具有動(dòng)態(tài)伸縮性,它能根據(jù)執(zhí)行任務(wù)的輕重自動(dòng)調(diào)整線程 池中線程的數(shù)量。文章的最后,我們給出一個(gè)本文給出了一個(gè)通用的線程池框架,該框架將與線程執(zhí)行相關(guān)的任務(wù)進(jìn)行了高層次的抽象,使之 與具體的執(zhí)行任務(wù)無關(guān)。另外該線程池具有動(dòng)態(tài)伸縮性,它能根據(jù)執(zhí)行任務(wù)的輕重自動(dòng)調(diào)整線程 池中線程的數(shù)量。文章的最后,我們給出一個(gè)簡單示例程序,通過該示例程序,我們會(huì)發(fā)現(xiàn),通 過該線程池框架執(zhí)行多線

2、程任務(wù)是多么的簡單。為什么需要線程池目前的大多數(shù)網(wǎng)絡(luò)服務(wù)器,包括 Web服務(wù)器、Email服務(wù)器以及數(shù)據(jù)庫服務(wù)器等都具有一個(gè)共同 點(diǎn),就是單位時(shí)間內(nèi)必須處理數(shù)目巨大的連接請求,但處理時(shí)間卻相對較短。傳統(tǒng)多線程方案中我們采用的服務(wù)器模型則是一旦接受到請求之后,即創(chuàng)建一個(gè)新的線程,由該 線程執(zhí)行任務(wù)。任務(wù)執(zhí)行完畢后,線程退出,這就是是“即時(shí)創(chuàng)建,即時(shí)銷毀”的策略。盡管與 創(chuàng)建進(jìn)程相比,創(chuàng)建線程的時(shí)間已經(jīng)大大的縮短,但是如果提交給線程的任務(wù)是執(zhí)行時(shí)間較短, 而且執(zhí)行次數(shù)極其頻繁,那么服務(wù)器將處于不停的創(chuàng)建線程,銷毀線程的狀態(tài)。我們將傳統(tǒng)方案中的線程執(zhí)行過程分為三個(gè)過程:T1、 T2、 T3T1:線程

3、創(chuàng)建時(shí)間T2:線程執(zhí)行時(shí)間,包括線程的同步等時(shí)間T3:線程銷毀時(shí)間那么我們可以看出,線程本身的開銷所占的比例為(T1+T3)/ (T1+T2+T3。) 如果線程執(zhí)行的時(shí)間很短的話,這比開銷可能占到20% 50%左右。如果任務(wù)執(zhí)行時(shí)間很頻繁的話,這筆開銷將是不可忽略 的。除此之外,線程池能夠減少創(chuàng)建的線程個(gè)數(shù)。通常線程池所允許的并發(fā)線程是有上界的,如果同 時(shí)需要并發(fā)的線程數(shù)超過上界,那么一部分線程將會(huì)等待。而傳統(tǒng)方案中,如果同時(shí)請求數(shù)目為 2000,那么最壞情況下,系統(tǒng)可能需要產(chǎn)生 2000 個(gè)線程。盡管這不是一個(gè)很大的數(shù)目,但是也 有部分機(jī)器可能達(dá)不到這種要求。因此線程池的出現(xiàn)正是著眼于減少線

4、程池本身帶來的開銷。線程池采用預(yù)創(chuàng)建的技術(shù),在應(yīng)用程 序啟動(dòng)之后,將立即創(chuàng)建一定數(shù)量的線程(N1),放入空閑隊(duì)列中。這些線程都是處于阻塞(Suspendec)狀態(tài),不消耗CPU但占用較小的內(nèi)存空間。當(dāng)任務(wù)到來后,緩沖池選擇一個(gè)空閑 線程,把任務(wù)傳入此線程中運(yùn)行。當(dāng) N1 個(gè)線程都在處理任務(wù)后,緩沖池自動(dòng)創(chuàng)建一定數(shù)量的新 線程,用于處理更多的任務(wù)。在任務(wù)執(zhí)行完畢后線程也不退出,而是繼續(xù)保持在池中等待下一次 的任務(wù)。當(dāng)系統(tǒng)比較空閑時(shí),大部分線程都一直處于暫停狀態(tài),線程池自動(dòng)銷毀一部分線程,回 收系統(tǒng)資源?;谶@種預(yù)創(chuàng)建技術(shù),線程池將線程創(chuàng)建和銷毀本身所帶來的開銷分?jǐn)偟搅烁鱾€(gè)具體的任務(wù)上, 執(zhí)行次數(shù)

5、越多,每個(gè)任務(wù)所分擔(dān)到的線程本身開銷則越小,不過我們另外可能需要考慮進(jìn)去線程 之間同步所帶來的開銷。構(gòu)建線程池框架一般線程池都必須具備下面幾個(gè)組成部分:線程池管理器 :用于創(chuàng)建并管理線程池工作線程 : 線程池中實(shí)際執(zhí)行的線程任務(wù)接口 :盡管線程池大多數(shù)情況下是用來支持網(wǎng)絡(luò)服務(wù)器,但是我們將線程執(zhí)行的任務(wù)抽象出來, 形成任務(wù)接口,從而是的線程池與具體的任務(wù)無關(guān)。任務(wù)隊(duì)列 :線程池的概念具體到實(shí)現(xiàn)則可能是隊(duì)列,鏈表之類的數(shù)據(jù)結(jié)構(gòu),其中保存執(zhí)行線程我們實(shí)現(xiàn)的通用線程池框架由五個(gè)重要部分組成CThreadManage, CThreadPoo,l CThread, CJob,CWorkerThread,

6、除此之外框架中還包括線程同步使用的類CThreadMutex和CCondition。CJob是所有的任務(wù)的基類,其提供一個(gè)接口 Run,所有的任務(wù)類都必須從該類繼承,同時(shí)實(shí)現(xiàn) Run方法。該方法中實(shí)現(xiàn)具體的任務(wù)邏輯。CThread是Linux中線程的包裝,其封裝了 Linux線程最經(jīng)常使用的屬性和方法,它也是一個(gè)抽象 類,是所有線程類的基類,具有一個(gè)接口Run。CWorkerThread是實(shí)際被調(diào)度和執(zhí)行的線程類,其從 CThread繼承而來,實(shí)現(xiàn)了 CThread中的Run 方法。CThreadPoo是線程池類,其負(fù)責(zé)保存線程,釋放線程以及調(diào)度線程。CThreadMa nage是線程池與用戶

7、的直接接口,其屏蔽了內(nèi)部的具體實(shí)現(xiàn)。CThreadMutex用于線程之間的互斥CCondition 則是條件變量的封裝,用于線程之間的同步它們的類的繼承關(guān)系如下圖所示:線程池的時(shí)序很簡單,如下圖所示。CThreadMa nage直接跟客戶端打交道,其接受需要?jiǎng)?chuàng)建的線程初始個(gè)數(shù),并接受客戶端提交的任務(wù)。這兒的任務(wù)是具體的非抽象的任務(wù)。CThreadMa nage的內(nèi)部實(shí)際上調(diào)用的都是CThreadPool的相關(guān)操作。CThreadPoo創(chuàng)建具體的線程,并把客戶端提交 的任務(wù)分發(fā)給CWorkerThread, CWorkerThread實(shí)際執(zhí)行具體的任務(wù)。理解系統(tǒng)組件下面我們分開來了解系統(tǒng)中的各個(gè)

8、組件。CThreadManageCThreadMa nage的功能非常簡單,其提供最簡單的方法,其類定義如下:classCThreadManageprivate:CThreadPool* m_Pool;int m_NumOfThread;protected: public:void SetParallelNum(int num);CThreadManage();CThreadManage(intnum);virtual CThreadManage();void Run(CJob*job,void* jobdata);void TerminateAll(void);其中 m_Pool 指向?qū)嶋H的

9、線程池; m_NumOfThread 是初始創(chuàng)建時(shí)候允許創(chuàng)建的并發(fā)的線程個(gè)數(shù)。 另外Run和TerminateAII方法也非常簡單,只是簡單的調(diào)用 CThreadPool的一些相關(guān)方法而已 其具體的實(shí)現(xiàn)如下 :CThreadManage:CThreadManage()m_NumOfThread = 10;m_Pool=new CThreadPool(m_NumOfThread);CThreadManage:CThreadManage(intnum)m_NumOfThread = num;m_Pool = new CThreadPool(m_NumOfThread); CThreadManage

10、:CThreadManage()if(NULL!= m_Pool)delete m_Pool;void CThreadManage:SetParallelNum(intnum) m_NumOfThread = num;void CThreadManage:Run(CJob*job,void* jobdata)m_Pool >Run(jobjobdata);void CThreadManage:TerminateAll(void)m_Pool >TerminateAII();CThreadCThread類實(shí)現(xiàn)了對Linux中線程操作的封裝,它是所有線程的基類,也是一個(gè)抽象類,提供了一

11、 個(gè)抽象接口 Run,所有的CThread都必須實(shí)現(xiàn)該Run方法。CThread的定義如下所示: classCThread private:int m_ErrCode;Semaphore m_ThreadSemaphore; /the inner semaphore, which is used to realizeunsigned long m_ThreadID;bool m_Detach; /The thread is detachedbool m_CreateSuspended; /if suspend after creatingchar* m_ThreadName;ThreadSta

12、tem_ThreadState; /the state of the thread protected:void SetErrcode(interrcode)m_ErrCode= errcode;static void* ThreadFunction(void*);public:CThread();CThread(boolcreatesuspended,bool detach);virtual CThread();virtual void Run(void)= 0;void SetThreadState(ThreadStatestate)m_ThreadState = state;bool T

13、erminate(void); /Terminate the threabool Start(void); /Start to execute the threadvoid Exit(void);bool Wakeup(void);ThreadState GetThreadState(void)return m_ThreadState;int GetLastError(void)return m_ErrCode;void SetThreadName(char* thrname)strcpy(m_ThreadName,thrname);char* GetThreadName(void)retur

14、n m_ThreadName;int GetThreadID(void)return m_ThreadID;bool SetPriority(int priority);int GetPriority(void);int GetConcurrency(void);void SetConcurrency(int num);bool Detach(void);bool Join(void);bool Yield(void);int Self(void);線程的狀態(tài)可以分為四種,空閑、忙碌、掛起、終止 (包括正常退出和非正常退出 )。由于目前Linux線程庫不支持掛起操作,因此,我們的此處的掛起操作

15、類似于暫停。如果線程創(chuàng)建后不想立 即執(zhí)行任務(wù),那么我們可以將其“暫?!?,如果需要運(yùn)行,則喚醒。有一點(diǎn)必須注意的是,一旦 線程開始執(zhí)行任務(wù),將不能被掛起,其將一直執(zhí)行任務(wù)至完畢。線程類的相關(guān)操作均十分簡單。線程的執(zhí)行入口是從 Start()函數(shù)開始,其將調(diào)用函數(shù)ThreadFunction, ThreadFunction 再調(diào)用實(shí)際的 Run 函數(shù),執(zhí)行實(shí)際的任務(wù)。CThreadPoolCThreadPool是線程的承載容器,一般可以將其實(shí)現(xiàn)為堆棧、單向隊(duì)列或者雙向隊(duì)列。在我們的系 統(tǒng)中我們使用STLVector對線程進(jìn)行保存。CThreadPool的實(shí)現(xiàn)代碼如下:classCThreadPoo

16、lfriend classCWorkerThread;private:unsigned int m_MaxNum; /the maxthread numthat cancreateatthesametimeunsignedintm_AvailLow;/The minnumofidlethread thatshoulekeptunsigned int m_AvailHigh; /The maxnumofidlethread that kept at the sametimeunsigned int m_AvailNum; /the normalthread numofidle num;unsig

17、ned int m_InitNum; /Normal thread num;protected:CWorkerThread* GetIdleThread(void);void AppendToIdleList(CWorkerThread* jobthread);void MoveToBusyList(CWorkerThread*idlethread);void MoveToIdleList(CWorkerThread* busythread);void DeleteIdleThread(int num);void CreateIdleThread(int num);public:CThread

18、Mutex m_BusyMutex; /when visit busylist,use m_BusyMutex to lock and unlockCThreadMutex m_IdleMutex; /when visit idle list,use m_IdleMutex to lock and unlockCThreadMutex m_JobMutex; /when visit job list,use m_JobMutex to lock and unlockCThreadMutex m_VarMutex;CCondition m_BusyCond;/m_BusyCond is used

19、 to sync busy thread listCCondition m_IdleCond; /m_IdleCond is used to sync idle thread listCCondition m_IdleJobCond; /m_JobCond is used to sync job listCCondition m_MaxNumCond;vector<CWorkerThread*> m_ThreadList;vector<CWorkerThread*>m_BusyList;/Thread Listvector<CWorkerThread*>m_

20、IdleList; /Idle ListCThreadPool();CThreadPool(intinitnum);virtual CThreadPool();void SetMaxNum(int maxnum)m_MaxNum = maxnum; int GetMaxNum(void)return m_MaxNum; void SetAvailLowNum(int minnum)m_AvailLow = minnum; int GetAvailLowNum(void)return m_AvailLow; void SetAvailHighNum(int highnum)m_AvailHigh

21、 = highnum; int GetAvailHighNum(void)return m_AvailHigh; int GetActualAvailNum(void)return m_AvailNum; int GetAllNum(void)return m_ThreadList.size(); int GetBusyNum(void)return m_BusyList.size(); void SetInitNum(int initnum)m_InitNum = initnum; int GetInitNum(void)return m_InitNum;void TerminateAll(

22、void);void Run(CJob*job,void* jobdata);CThreadPool:CThreadPool()m_MaxNum = 50;m_AvailLow = 5;m_InitNum=m_AvailNum = 10 ;m_AvailHigh = 20;m_BusyList.clear();m_IdleList.clear();for(int i=0;i<m_InitNum;i+)CWorkerThread* thr = new CWorkerThread();thr >SetThreadPool(this);AppendToIdleList(thr);thr

23、>Start();CThreadPool:CThreadPool(intinitnum)assert(initnum>0 && initnum<=30);m_MaxNum = 30;m_AvailLow = i nitnum 10>0?i nitn um 10:3;m_InitNum=m_AvailNum =initnum ;m_AvailHigh=initnum+10;m_BusyList.clear();m_IdleList.clear();for(int i=0;i<m_InitNum;i+)CWorkerThread* thr = newC

24、WorkerThread();AppendToIdleList(thr);thr >SetThreadPool(this);thr >Start();/begin the thread,the thread wait for jobCThreadPool:CThreadPool()TerminateAll();void CThreadPool:TerminateAll()for(int i=0;i < m_ThreadList.size();i+)CWorkerThread* thr = m_ThreadListi;thr >Join();return;CWorkerT

25、hread* CThreadPool:GetIdleThread(void)while(m_IdleList.size() =0 )m_IdleCond.Wait();m_IdleMutex.Lock();if(m_IdleList.size() > 0 )CWorkerThread* thr = (CWorkerThread*)m_IdleList.front();printf("Get Idle thread %dn”,thr >GetThreadlD();m_IdleMutex.Unlock();return thr;m_IdleMutex.Unlock();ret

26、urn NULL;/add an idle thread to idle listvoid CThreadPool:AppendToIdleList(CWorkerThread*jobthread)m_IdleList.push_back(jobthread);m_IdleMutex.Lock();m_ThreadList.push_back(jobthread);m_IdleMutex.Unlock();/move and idle thread to busy threadvoid CThreadPool:MoveToBusyList(CWorkerThread*idlethread) m

27、_BusyMutex.Lock();m_BusyList.push_back(idlethread);m_AvailNum -;-m_BusyMutex.Unlock();m_IdleMutex.Lock();vector<CWorkerThread*>:iterator pos;pos = find(m_IdleList.begin(),m_IdleList.end(),idlethread);if(pos !=m_IdleList.end()m_IdleList.erase(pos);m_IdleMutex.Unlock();void CThreadPool:MoveToIdl

28、eList(CWorkerThread*busythread)m_IdleList.push_back(busythread);m_IdleMutex.Lock();m_AvailNum+;m_IdleMutex.Unlock();m_BusyMutex.Lock();vector<CWorkerThread*>:iterator pos;pos = find(m_BusyList.begin(),m_BusyList.end(),busythread);if(pos!=m_BusyList.end()m_BusyList.erase(pos);m_BusyMutex.Unlock

29、();m_IdleCond.Signal();m_MaxNumCond.Signal();/create num idle thread and put them to idlelistvoid CThreadPool:CreateIdleThread(intnum)for(int i=0;i<num;i+)CWorkerThread* thr =new CWorkerThread();thr >SetThreadPool(this);AppendToIdleList(thr);m_VarMutex.Lock();m_AvailNum+;m_VarMutex.Unlock();th

30、r >Start();/begin the thread,the thread wait for jobvoid CThreadPool:DeleteIdleThread(intnum)printf("Enter into CThreadPool:DeleteIdleThreadn");m_IdleMutex.Lock();printf("Delete Num is %dn",num);for(int i=0;i<num;i+)CWorkerThread* thr;if(m_IdleList.size() > 0 )thr = (CWo

31、rkerThread*)m_IdleList.front();printf("Get Idle thread %dn”,thr >GetThreadlD();vector<CWorkerThread*>:iterator pos;pos = find(m_IdleList.begin(),m_IdleList.end(),thr);if(pos!=m_IdleList.end()m_IdleList.erase(pos);m_AvailNum -;-printf("The idle thread availablenum:%dn",m_Avail

32、Num);printf("The idlelist num:%d n",m_IdleList.size();m_IdleMutex.Unlock();void CThreadPool:Run(CJob*job,void* jobdata)assert(job!=NULL);/if the busythread num adds to m_MaxNum,so we should waitif(GetBusyNum() = m_MaxNum)m_MaxNumCond.Wait();if(m_IdleList.size()<m_AvailLow)if(GetAIINum()

33、+m_lnitNum m_ldleList.size()v m_MaxNum )CreateldleThread(mnitNum mdIeList.size();elseCreateldleThread(m_MaxNumGetAIINum();CWorkerThread* idlethr = GetldleThread();if(idlethr !=NULL)idlethr >m_WorkMutex.Lock();MoveToBusyList(idlethr);idlethr >SetThreadPool(this);job >SetWorkThread(idlethr);p

34、rintf("Job issetto thread %d n",idlethr >GetThreadlD();idlethr >SetJob(job,jobdata);在CThreadPool中存在兩個(gè)鏈表,一個(gè)是空閑鏈表,一個(gè)是忙碌鏈表。Idle鏈表中存放所有的空閑進(jìn)程,當(dāng)線程執(zhí)行任務(wù)時(shí)候,其狀態(tài)變?yōu)槊β禒顟B(tài),同時(shí)從空閑鏈表中刪除,并移至忙碌鏈表 中。在CThreadPooI的構(gòu)造函數(shù)中,我們將執(zhí)行下面的代碼:for(int i=0;i<m_InitNum;i+)CWorkerThread* thr =new CWorkerThread();AppendToIdleList(thr);thr >SetThreadPool(this);thr >Start(); /begin the thread,the thread wait for job在該代碼中,我們將創(chuàng)建 mnitNum個(gè)線程,創(chuàng)建之后即調(diào)用 AppendToldleList放入Idle鏈表 中,由于目前沒有任務(wù)分發(fā)給這些線程,因此線程執(zhí)行 Start 后將自己掛起。事實(shí)上,線程池中容納的線程數(shù)目并不

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論