日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

利用C++语言设计可扩展线程池

發(fā)布時(shí)間:2025/3/15 c/c++ 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 利用C++语言设计可扩展线程池 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  摘要:在各種業(yè)務(wù)解決方案的設(shè)計(jì)中,服務(wù)器處理任務(wù)的效率是衡量方案優(yōu)劣的一個(gè)重要標(biāo)準(zhǔn)。使用多線程技術(shù)并發(fā)處理任務(wù)是提高服務(wù)器效率的一個(gè)主要手段。但是頻繁的線程創(chuàng)建、銷毀和任務(wù)的分配也會(huì)降低系統(tǒng)效率。本文設(shè)計(jì)了一個(gè)通用的線程池,根據(jù)不同服務(wù)器所處理的任務(wù)的特點(diǎn),可以設(shè)置對(duì)應(yīng)的線程池參數(shù),最大幅度的提高系統(tǒng)性能。

  關(guān)鍵字:線程池多線程任務(wù)虛函數(shù)異常

  概述

  在各種業(yè)務(wù)解決方案的設(shè)計(jì)過程中,服務(wù)器處理任務(wù)的效率往往決定了方案的成敗。多線程處理任務(wù)是提高服務(wù)器效率的主要手段,它提高了對(duì)服務(wù)器資源的利用,使得任務(wù)可以并發(fā)處理。但如果服務(wù)器處理的任務(wù)的特點(diǎn)是輕量級(jí)、頻率高,那么線程的創(chuàng)建與銷毀會(huì)非常頻繁,而系統(tǒng)用于處理線程的創(chuàng)建與銷毀的開銷會(huì)占相當(dāng)大的比重,反而降低了系統(tǒng)的效率。通過線程池技術(shù),可以減少頻繁的線程的創(chuàng)建與銷毀對(duì)系統(tǒng)性能的影響。

  線程池是預(yù)先創(chuàng)建線程的一種技術(shù)。線程池在還沒有任務(wù)到來之前,創(chuàng)建一定數(shù)量(N1)的線程,放入空閑隊(duì)列中。這些線程都是處于阻塞(Suspended)狀態(tài),不消耗CPU,但占用較小的內(nèi)存空間。當(dāng)任務(wù)到來后,緩沖池選擇一個(gè)空閑線程,把任務(wù)傳入此線程中運(yùn)行。當(dāng)N1個(gè)線程都在處理任務(wù)后,緩沖池自動(dòng)創(chuàng)建一定數(shù)量的新線程,用于處理更多的任務(wù)。當(dāng)系統(tǒng)比較空閑時(shí),大部分線程都一直處于暫停狀態(tài),線程池自動(dòng)銷毀一部分線程,回收系統(tǒng)資源。

  通用線程緩沖池的設(shè)計(jì),不僅要實(shí)現(xiàn)上述功能,還要考慮此設(shè)計(jì)的可移植性,減少重復(fù)開發(fā)。設(shè)計(jì)中需要考慮的重點(diǎn)是:

任務(wù)對(duì)象的通用性;
線程創(chuàng)建和銷毀策略;
任務(wù)的分配策略。
  分析與設(shè)計(jì)

  1、任務(wù)對(duì)象的通用性

  不同的業(yè)務(wù)解決方案有各自獨(dú)特的任務(wù)處理方法,任務(wù)的劃分上也就千差萬別。為了使得在處理任務(wù)對(duì)象的時(shí)候達(dá)到一定程度的通用性,任務(wù)對(duì)象的設(shè)計(jì)上必須與實(shí)際任務(wù)的處理邏輯完全無關(guān)。從任務(wù)執(zhí)行的角度看,任務(wù)不過是處理流程的一次或者多次執(zhí)行的過程,可以這樣來定義任務(wù)接口:

class Task

{

public:

Task();

virtual ~Task();

virtual bool run() = 0;

};

  Task類是所有任務(wù)類的基類,其中的純虛函數(shù)run()是任務(wù)流程的入口,工作線程在處理任務(wù)的時(shí)候就從此處開始執(zhí)行任務(wù)的處理流程。設(shè)計(jì)一個(gè)新的任務(wù)時(shí),只需要繼承Task接口,新的任務(wù)就可以放入線程池中執(zhí)行。

  任務(wù)的創(chuàng)建、執(zhí)行和銷毀這樣來設(shè)計(jì):

  (1)任務(wù)在其需要的時(shí)候才創(chuàng)建。任務(wù)的創(chuàng)建通過new操作,動(dòng)態(tài)創(chuàng)建具體的任務(wù)對(duì)象,然后傳入線程池,由線程池自動(dòng)分配線程來執(zhí)行此任務(wù)。

  (2)任務(wù)是否執(zhí)行完畢由其自身來決定。一個(gè)未知任務(wù)什么時(shí)候執(zhí)行完畢是不可能預(yù)測(cè)的,必須任務(wù)本身來決定。這個(gè)策略通過,Task::run()的返回值來實(shí)現(xiàn)。當(dāng)工作線程執(zhí)行一次任務(wù)時(shí),如果返回值為true,表示任務(wù)執(zhí)行完畢,就用delete操作銷毀此任務(wù);如果返回值為false,表示任務(wù)需要執(zhí)行的工作并未完成,繼續(xù)執(zhí)行此任務(wù)。

  這樣的策略,使得在設(shè)計(jì)新的任務(wù)處理流程的時(shí)候,不需要過多的關(guān)心任務(wù)的接口規(guī)范,只需要在新任務(wù)類的構(gòu)造函數(shù)中初始化各種資源,在新任務(wù)類的析構(gòu)函數(shù)中回收資源,在run()方法中實(shí)現(xiàn)主要的處理邏輯,那么新的任務(wù)類即可在線程池中執(zhí)行。

  2、線程的創(chuàng)建與銷毀

  線程緩沖池中的維持的線程數(shù)量應(yīng)該按照任務(wù)處理的需求來定。

  在緩沖池剛剛建立時(shí),線程池中有一定數(shù)量(N1)的已創(chuàng)建好的線程,這樣可以使得新任務(wù)可以及時(shí)的得到執(zhí)行。比如,某客戶端在向服務(wù)器發(fā)送登陸請(qǐng)求的時(shí)候,這樣一個(gè)請(qǐng)求使得服務(wù)器通常需要?jiǎng)?chuàng)建好幾個(gè)相互有關(guān)聯(lián)的任務(wù)。也就是說,客戶端與服務(wù)器端的一次交互,通常會(huì)產(chǎn)生一定數(shù)量的任務(wù)。根據(jù)一個(gè)服務(wù)器所處理的業(yè)務(wù),估計(jì)出平均情況下,一次業(yè)務(wù)產(chǎn)生的任務(wù)數(shù)量N2。那么N1應(yīng)該是N2的整數(shù)倍,N1=N2×n1,減少由于線程不夠而再創(chuàng)建線程的概率,才能使得服務(wù)器在業(yè)務(wù)處理初期最為高效。

  在線程緩沖池中的所有線程都處于繁忙狀態(tài)的時(shí)候,線程池就會(huì)創(chuàng)建新的線程,設(shè)創(chuàng)建N3個(gè)。由以上分析,為了減少由于線程不夠而再創(chuàng)建線程的概率,N3也應(yīng)該是N2的整數(shù)倍,N3=N2×n2。

  當(dāng)服務(wù)器業(yè)務(wù)減少,出現(xiàn)大量線程閑置的情況,就應(yīng)該銷毀一部分線程。很顯然,這里應(yīng)該使用超時(shí)策略,當(dāng)某些線程在超過時(shí)間T仍然處于閑置狀態(tài),就銷毀一部分空閑線程。設(shè)銷毀N4個(gè)空閑線程,為了減少由于線程不夠而再創(chuàng)建線程的概率,N4也應(yīng)該是N2的整數(shù)倍,N4=N2×n3。當(dāng)然,為了使得新任務(wù)及時(shí)得到處理,即使服務(wù)器一直處于空閑,也應(yīng)該保留N1個(gè)線程。
  3、任務(wù)分配策略

  在業(yè)務(wù)處理中,會(huì)有各種各樣的任務(wù)對(duì)象,這些業(yè)務(wù)對(duì)象對(duì)系統(tǒng)資源的使用也不同。這些任務(wù),無論其空間復(fù)雜度如何,從線程執(zhí)行任務(wù)這一角度來看,應(yīng)該關(guān)心的主要是時(shí)間復(fù)雜度。

  線程緩沖池在接收到新任務(wù)的時(shí)候,首先要尋找空閑線程,傳入新任務(wù),然后執(zhí)行任務(wù),最后還要?jiǎng)h除任務(wù),置空閑線程的標(biāo)志。尋找空閑線程、傳入任務(wù)、最后的清理工作,這些都是為了執(zhí)行任務(wù)而產(chǎn)生的額外開銷,如果所執(zhí)行的任務(wù)大多數(shù)都是輕量級(jí)任務(wù),那么額外開銷帶來的資源浪費(fèi)就顯得很突出了。為了解決這個(gè)問題,可以給一個(gè)線程傳入N5個(gè)輕量級(jí)任務(wù),這一個(gè)線程依次執(zhí)行N5個(gè)輕量級(jí)任務(wù),由于都是在很短時(shí)間內(nèi)完成,并不影響任務(wù)響應(yīng)的及時(shí)性。顯然,N5≥1。

  實(shí)現(xiàn)

  由于源代碼的篇幅關(guān)系,并不能把所有代碼一一列舉,這里以偽代碼的形式給出線程緩沖池在線程的創(chuàng)建、銷毀、任務(wù)分配以及任務(wù)執(zhí)行方面的流程。

  (1) 線程池任務(wù)分配主循環(huán)(也是一個(gè)線程)

  這里除了任務(wù)分配算法外也包括了部分線程的創(chuàng)建與銷毀的算法。

for(;;) {

pThread = GetIdleThread();// 檢查空閑線程隊(duì)列

if( pThread != NULL ) {

if( CheckNewTask() ) {// 有新任務(wù)

TaskList tl;

GetTask( tl ); // 取得一定數(shù)量的任務(wù)

AddTaskToThread( pTask, tl );// 把任務(wù)傳入線程

continue; // 繼續(xù)循環(huán)

}

}

if( pThread == NULL && nThread < THREAD_MAX )// 沒有空閑線程了

CreateNewThread();// 創(chuàng)建新線程

continue;// 繼續(xù)循環(huán)

}

// 沒有要處理的任務(wù)或者已經(jīng)到達(dá)線程數(shù)的上限,進(jìn)入超時(shí)等待

if( WaitForTaskOrThreadTimeout() ) {

if( IncrIdleTime() > IDLE_MAX ) { // 系統(tǒng)空閑,計(jì)時(shí)

// 系統(tǒng)長時(shí)間處于空閑,銷毀一定數(shù)量的空閑線程

DecrIdleThread();

}

}

else

return 0;// 線程終止

}

  (2) 工作線程的任務(wù)執(zhí)行流程

for(;;) {

// 檢查任務(wù)隊(duì)列是否有任務(wù)要運(yùn)行

if( !CheckTaskQueue() ) { // 隊(duì)列中沒有任務(wù)

pPool->OnTaskIdle( this ); // 通知線程池,此線程已經(jīng)空閑

if( WaitForTask() )

continue;// 繼續(xù)循環(huán)

else

return 0;// 終止線程

} else { // 有任務(wù)需要運(yùn)行

pTask = GetTask(); // 取得新任務(wù)

try {

while( !pTask->Run() ) {

// 此處循環(huán)體為空,不斷運(yùn)行直到任務(wù)執(zhí)行完畢

}

}

catch( … ) {

WriteLog( … ); // 執(zhí)行任務(wù)時(shí)產(chǎn)生異常,記錄入日志

}

delete pTask; // 任務(wù)執(zhí)行完畢,刪除此任務(wù)

}

}

  在任務(wù)執(zhí)行的核心部分,使用了try-catch控制塊進(jìn)行異常捕獲。雖然異常會(huì)對(duì)程序速度有很略微的影響,但是因?yàn)橐獔?zhí)行的任務(wù)是未知的,不能保證任務(wù)可以正常執(zhí)行。因?yàn)橐粋€(gè)任務(wù)的異常而導(dǎo)致服務(wù)器的服務(wù)程序崩潰,這是絕對(duì)不允許的。使用異常捕獲不僅可以保證服務(wù)器流程的順利執(zhí)行,而且把異常信息存入日志文件,還可以跟蹤錯(cuò)誤。

  性能測(cè)試

  為了檢驗(yàn)此線程池的性能是否和預(yù)期相同,并且分析出線程池的不同參數(shù)配置對(duì)系統(tǒng)性能的影響,特編寫了測(cè)試程序?qū)θM參數(shù)進(jìn)行了測(cè)試,測(cè)試結(jié)果如圖1所示:




  橫坐標(biāo)是任務(wù)數(shù)量;縱坐標(biāo)是消耗時(shí)間,以 秒(s)為單位。

  參數(shù)1:N2 = 1, N 5 = 1; 參數(shù)2:N2 = 5, N5 = 1; 參數(shù)3:N2 = 5, N5 = 5

  測(cè)試中,系統(tǒng)的總的線程數(shù)限制為500,任務(wù)都是5ms。這里只針對(duì)N2和N5進(jìn)行測(cè)試,N2是平均情況下系統(tǒng)每次向線程池中增加的任務(wù)數(shù)量,N5是每個(gè)線程一次執(zhí)行任務(wù)數(shù)量。

  在任務(wù)量比較小的情況下,三者的對(duì)系統(tǒng)性能的占用基本上相等。但是當(dāng)任務(wù)量很巨大的時(shí)候,參數(shù)1比參數(shù)2效率要稍微高出一些,而參數(shù)3的執(zhí)行效率幾乎是前兩者的一倍。

  因?yàn)槎际禽p量級(jí)任務(wù),所以N2的變化對(duì)系統(tǒng)效率的影響并不大,而N5的影響就很顯著。

   結(jié)束語

  通過測(cè)試可以看出,在服務(wù)器中使用線程池后,并不意味著系統(tǒng)性能就一定可以提升。不同系統(tǒng)的任務(wù)有著各自不同的特點(diǎn),這就需要根據(jù)服務(wù)器任務(wù)的特點(diǎn)進(jìn)一步調(diào)整緩沖池的一些關(guān)鍵參數(shù),才能最大程度的提高系統(tǒng)效率。這些參數(shù)就是上面分析過程中的N1、N2、N3、N4、N5、n1、n2、n3。

總結(jié)

以上是生活随笔為你收集整理的利用C++语言设计可扩展线程池的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。