




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
非常精簡的線程池實(shí)現(xiàn)(一)——使用互斥鎖和條件變量線程池的含義跟它的名字一樣,就是一個(gè)由許多線程組成的池子。有了線程池,在程序中使用多線程變得簡單。我們不用再自己去操心線程的創(chuàng)建、撤銷、管理問題,有什么要消耗大量時(shí)間的任務(wù)通通直接扔到線程池里就好了,然后我們的主程序(主線程)可以繼續(xù)干自己的事去,線程池里面的線程會自動去執(zhí)行這些任務(wù)。另一方面,線程池提升了多線程程序的性能。我們不需要在大量任務(wù)需要執(zhí)行時(shí)現(xiàn)創(chuàng)建大量線程,然后在任務(wù)結(jié)束時(shí)又銷毀大量線程,因?yàn)榫€程池里面的線程都是現(xiàn)成的而且能夠重復(fù)使用。一個(gè)理想的線程池能夠合理地動態(tài)調(diào)節(jié)池內(nèi)線程數(shù)量,既不會因?yàn)榫€程過少而導(dǎo)致大量任務(wù)堆積,也不會因?yàn)榫€程過多了而增加額外的系統(tǒng)開銷。線程池看上去很神奇的樣子,那它是怎么實(shí)現(xiàn)的呢?線程這么虛渺在的東西也能像有形的物品一樣圈在一個(gè)池子里?在只知道線程池這個(gè)名字的時(shí)候,我心里的疑惑就是這樣的。其實(shí)線程池的原理非常簡單,它就是一個(gè)非常典型的生產(chǎn)者消費(fèi)者同步問題。如果不知道我說的這個(gè)問題也不要緊,我下面就解釋。根據(jù)剛才描述的線程池的功能,可以看出線程池至少有兩個(gè)主要動作,一個(gè)是主程序不定時(shí)地向線程池添加任務(wù),另一個(gè)是線程池里的線程領(lǐng)取任務(wù)去執(zhí)行。且不論任務(wù)和執(zhí)行任務(wù)是個(gè)什么概念,但是一個(gè)任務(wù)肯定只能分配給一個(gè)線程執(zhí)行。這樣就可以簡單猜想線程池的一種可能的架構(gòu)了:主程序執(zhí)行入隊(duì)操作,把任務(wù)添加到一個(gè)隊(duì)列里面;池子里的多個(gè)工作線程共同對這個(gè)隊(duì)列試圖執(zhí)行出隊(duì)操作,這里要保證同一時(shí)刻只有一個(gè)線程出隊(duì)成功,搶奪到這個(gè)任務(wù),其他線程繼續(xù)共同試圖出隊(duì)搶奪下一個(gè)任務(wù)。所以在實(shí)現(xiàn)線程池之前,我們需要一個(gè)隊(duì)列,我為這個(gè)線程池配備的隊(duì)列單獨(dú)放到了另一篇博客一個(gè)通用純隊(duì)列的實(shí)現(xiàn)中。這里的生產(chǎn)者就是主程序,生產(chǎn)任務(wù)(增加任務(wù)),消費(fèi)者就是工作線程,消費(fèi)任務(wù)(執(zhí)行、減少任
務(wù))。因?yàn)檫@里涉及到多個(gè)線程同時(shí)訪問一個(gè)隊(duì)列的問題,所以我們需要互斥鎖來保護(hù)隊(duì)列,同時(shí)還需要條件變量來處理主線程通知任務(wù)到達(dá)、工作線程搶奪任務(wù)的問題。如果不熟悉條件變量,我在另一篇博客LinuxC語言多線程庫Pthread中條件變量的的正確用法逐步詳解中作了詳細(xì)說明。準(zhǔn)備工作都差不多了,可以開始設(shè)計(jì)線程池了。一個(gè)最簡單線程池應(yīng)該有什么功能呢?對于使用者來說,除了創(chuàng)建和銷毀線程池,最簡單的情況下只需要一個(gè)功能一一添加任務(wù)。對于線程池自己來說,最簡單的情況下不需要動態(tài)調(diào)節(jié)線程數(shù)量,不需要考慮線程同步、線程死鎖等等一大堆麻煩的問題。所以最后的線程池定義為:創(chuàng)建線程池時(shí)指定線程池中應(yīng)該固定包含多少工作線程,添加任務(wù)就是向線程池添加一個(gè)任務(wù)函數(shù)指針和任務(wù)函數(shù)需要的參數(shù)——這跟線程庫中的普通線程創(chuàng)建函數(shù)是一樣針和任務(wù)函數(shù)需要的參數(shù)——這跟線程庫中的普通線程創(chuàng)建函數(shù)是一樣的。根據(jù)這套線程池 ,我們使用線程池的應(yīng)用程序應(yīng)該是這個(gè)套路:#include<unistd.h>#include<pthread.h>void*test(void*arg){inti;for(i=0;i<5;i++){printf("tid:%ldtask:%ld\n",pthread_self(),(long)arg);fflush(stdout);sleep(2);}returnNULL;}intmain(){longi=0;thread_pool_tpool;pool=thread_pool_create(2);for(i=0;i<5;i++){thread_pool_add_task(pool,test,(void*)i);}puts("pressentertoterminate...");getchar();thread_pool_destroy(pool);return0;
上面這個(gè)測試程序向線程池添加了個(gè)相同的任務(wù),每個(gè)任務(wù)耗時(shí)秒,但是線程池中只有個(gè)工作線呈,所以程序的運(yùn)行結(jié)果是兩個(gè)工作線程輪流把個(gè)任務(wù)挨個(gè)做完。顯示到屏幕上就是:前秒兩個(gè)工作線程輪流輸出自己的線程和當(dāng)前任務(wù)的任務(wù)號和,各輸出次;第二個(gè)秒兩個(gè)工作線程輪流輸出自己的線程和當(dāng)前任務(wù)的任務(wù)號和3……在這期間,主程序輸出“pressentertoterminate...”并等待用戶輸入,任何時(shí)候都可以按回車讓主程序繼續(xù)往下,這樣會強(qiáng)制終止所有工作線程并銷毀線程池,最后程序退出。test程序運(yùn)行效果截圖如下:最后就是線程池真正的實(shí)現(xiàn)了:treapoo.inetreapooin eee.inesti.in eptrea.str ttreapoonsineinttrea ontptreattreaseettassptreamtetoptreaonttasreaptreaonttasreastructtask{void*(*routine)(void*arg);void*arg;};staticvoidcleanup(pthread_mutex_t*lock){pthread_mutex_unlock(lock);}staticvoid*worker(thread_pool_tpool){structtask*t;while(1){pthread_mutex_lock(&pool->lock);pthread_cleanup_push((void(*)(void*))cleanup,&pool->lock);while(queue_isempty(pool->tasks)){pthread_cond_wait(&pool->task_ready,&pool->lock);/*Aconditionwait(whethertimedornot)isacancellationpoint...aside-effectofactinguponacancellationrequestwhileinaconditionwaitisthatthemutexis(ineffect)re-acquiredbeforecallingthefirstcancellationcleanuphandler.*/}t=(structtask*)queue_dequeue(pool->tasks);pthread_cleanup_pop(0);pthread_mutex_unlock(&pool->lock);t->routine(t->arg);/*todo:reportreturnedvalue*/free(t);}returnNULL;}thread_pool_tthread_pool_create(unsignedintthread_count){unsignedinti;thread_pool_tpool=NULL;pool=(thread_pool_t)malloc(sizeof(structthread_pool));pool->thread_count=thread_count;pool->threads=(pthread_t*)malloc(sizeof(pthread_t)*thread_count);pool->tasks=queue_create();pthread_mutex_init(&pool->lock,NULL);pthread_cond_init(&pool->task_ready,NULL);for(i=0;i<thread_count;i++){pthread_create(pool->threads+i,NULL,(void*(*)(void*))worker,pool);}returnpool;}voidthread_pool_add_task(thread_pool_tpool,void*(*routine)(void*arg),void*arg){structtask*t;pthread_mutex_lock(&pool->lock);t=(structtask*)queue_enqueue(pool->tasks,sizeof(structtask));上面的 函數(shù)就是工作線程函數(shù),所有的工作線程都在執(zhí)行著這個(gè)函數(shù)。它首先在互斥鎖和條件變量的保護(hù)下從任務(wù)隊(duì)列中取出一個(gè)任務(wù),這個(gè)任務(wù)實(shí)際上是一個(gè)函數(shù)指針和調(diào)用函數(shù)所需的參數(shù),所以執(zhí)行任務(wù)就很簡單了——用任務(wù)參數(shù)調(diào)用任務(wù)函數(shù)。函數(shù)返回以后,工作線程繼續(xù)去搶任務(wù)。這里沒有處理任務(wù)函數(shù)的返回值問題,理論上任務(wù)函數(shù)返回以后線程池應(yīng)該用某種機(jī)制通知主程序,然后主程序獲取通過某種手段獲取返回值,但這明顯不是一個(gè)最簡單的線程池需要操心的事。實(shí)際上,應(yīng)用程序可以通過全局變量或傳入的參數(shù)指針,加上額外的線程同步代碼解決返回值的通知和獲取問題。還有一點(diǎn)需要注意,最后線程池銷毀
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 配件買賣合同
- 湖北省十堰市2024-2025學(xué)年高二上學(xué)期1月期末地理試題 含解析
- 日常辦公事務(wù)處理文書詳案
- 融資借款合同協(xié)議書
- 數(shù)據(jù)傳輸效率評估表
- 產(chǎn)品分銷合同協(xié)議規(guī)范書
- 中學(xué)生科普知識解讀征文
- 電商平臺在線客服機(jī)器人技術(shù)支持協(xié)議
- 《現(xiàn)代酒店管理基礎(chǔ)》(第二版)課件 任務(wù)9 酒店集團(tuán)化管理
- 幼兒啟蒙成語故事解讀
- 機(jī)械基礎(chǔ)全冊教案第四版
- 《瘋狂動物城》全本臺詞中英文對照
- 大班語言猴子過河教案反思
- 同位語從句和定語從句
- 醫(yī)院OSCE考站建設(shè)需求
- 10以內(nèi)加減法口算題(13套100道題直接打印)
- 十年免還協(xié)議合同
- 中國建筑三鐵六律行為安全準(zhǔn)則培訓(xùn)ppt
- 斷橋門聯(lián)窗施工方案
- (2023版)高中化學(xué)新課標(biāo)知識考試題庫大全(含答案)
- 北師大三年級數(shù)學(xué)下冊計(jì)算練習(xí)(每天20道)
評論
0/150
提交評論