C++多线程快速入门(五)简单线程池设计
目錄
- 設(shè)計思路
- 主線程運行邏輯
- task以及taskpool設(shè)計
- 詳細流程講解
- 完整代碼
- 打印結(jié)果
- 往期回顧
設(shè)計思路
線程池實際上就是一組線程,當我們需要異步執(zhí)行一些任務(wù)時,經(jīng)常要通過OS頻繁創(chuàng)建和銷毀線程,不如直接創(chuàng)建一組在程序生命周期內(nèi)不會退出的線程。
當有任務(wù)需要被執(zhí)行時,線程可以自動地去拿任務(wù)并執(zhí)行,在沒有任務(wù)時,線程處于阻塞或者睡眠狀態(tài)。
我們選擇隊列存放任務(wù),main函數(shù)中的thread作為任務(wù)的生產(chǎn)者,從隊列尾部插入任務(wù)。線程池中的線程作為消費者,從隊列頭部獲取任務(wù)。
復(fù)雜考慮的話,當線程池的線程在處理任務(wù)的過程中也產(chǎn)生了關(guān)聯(lián)任務(wù),那么這個線程也是消費者。
隊列也可以設(shè)計得更加具有實用性,例如可以根據(jù)任務(wù)的優(yōu)先級設(shè)計多個隊列,然后線程根據(jù)優(yōu)先級獲取線程(也就是先查詢高優(yōu)先級的隊列,為空再去查詢低優(yōu)先級的隊列)。
綜上,我們的設(shè)計中會有多個線程訪問任務(wù)隊列,所以我們要解決線程池創(chuàng)建、向隊列投放任務(wù)、從隊列中獲取任務(wù)的線程互斥性。
同時線程池的清理、退出線程池中的工作線程、清理任務(wù)隊列,也是需要考慮的。
并且,為了能夠詳細獲知多線程獲取多任務(wù)的流程,我們需要對taskID和threadID進行輸出打印,std::cout并不是線程安全的,所以我們也要實現(xiàn)互斥地cout。
這里我們統(tǒng)一使用互斥量std::mutex+lock來實現(xiàn)互斥性
主線程運行邏輯
task以及taskpool設(shè)計
Task:
TaskPool:
內(nèi)部變量:
詳細流程講解
1、創(chuàng)建線程池對象時,調(diào)用構(gòu)造函數(shù)TaskPool(),并初始化布爾類型的標志m_bRunning為false,表示此時線程池對象中的線程不工作
2、調(diào)用線程池對象的初始化函數(shù)init(),這里默認的線程數(shù)為5。
- m_bRunning置為true,表示線程池對象中的線程應(yīng)該開始運行了
- 然后通過for循環(huán),每次構(gòu)造一個新的線程對象,并且綁定一個線程函數(shù)TaskPool::threadFunc,創(chuàng)建之后線程就開始工作了。然后打印出當前的線程id,注意此時需要上鎖,保證cout輸出正常。然后將線程對象送入m_threads數(shù)組
3、接下來看看構(gòu)造出來的每個線程在干啥:
4、for循環(huán),創(chuàng)建10個Task對象,然后調(diào)用addTask方法,將task送入線程池中的任務(wù)隊列。顯然push操作是互斥的,所以需要先上鎖。然后打印任務(wù)id和線程id,最后通過條件變量的notify_one方法,通知一個掛起的線程去消費隊列里面的任務(wù)。
5、等待一段時間
6、調(diào)用線程池對象的stop方法,先設(shè)置m_bRunning標志為false,然后通過條件變量的notify_all方法,通知掛起的或者正在運行的所有線程,結(jié)束線程函數(shù)運行。然后等待所有線程join之后,退出。
7、跳出主線程,開始調(diào)用TaskPool對象的析構(gòu)函數(shù),也就是執(zhí)行removeAllTasks方法,也就是將任務(wù)隊列里面的存的task指針進行reset,也就是減引用計數(shù),shared_ptr指針如果引用計數(shù)減為0,會自動調(diào)用析構(gòu)函數(shù)。為了線程安全,我們同樣需要對這塊代碼進行加鎖。
完整代碼
c++實現(xiàn)簡單線程池代碼
打印結(jié)果
Init a thread, id: 2 Init a thread, id: 3 Init a thread, id: 4 Init a thread, id: 5 Init a thread, id: 6 add a Task, id: 0, thread id is: 1 add a Task, id: 1, thread id is: 1 add a Task, id: 2, thread id is: 1 handle a task ,TaskID is: 1, thradID is:3 a task destructed , TaskID is: 1, thradID is:3 handle a task ,TaskID is: 2, thradID is:4 a task destructed , TaskID is: 2, thradID is:4 handle a task ,TaskID is: 0, thradID is:2 a task destructed , TaskID is: 0, thradID is:2 add a Task, id: 3, thread id is: 1 handle a task ,TaskID is: 3, thradID is:3 a task destructed , TaskID is: 3, thradID is:3 handle a task ,TaskID is: 4, thradID is:5 add a Task, id: 4, thread id is: 1 a task destructed , TaskID is: 4, thradID is:1 add a Task, id: 5, thread id is: 1 handle a task ,TaskID is: 5, thradID is:4 a task destructed , TaskID is: 5, thradID is:4 add a Task, id: 6, thread id is: 1 handle a task ,TaskID is: 6, thradID is:4 a task destructed , TaskID is: 6, thradID is:4 handle a task ,TaskID is: 7, thradID is:2 add a Task, id: 7, thread id is: 1 a task destructed , TaskID is: 7, thradID is:1 add a Task, id: 8, thread id is: 1 add a Task, id: 9, thread id is: 1 handle a task ,TaskID is: 9, thradID is:6 a task destructed , TaskID is: 9, thradID is:6 handle a task ,TaskID is: 8, thradID is:5 a task destructed , TaskID is: 8, thradID is:5 exit thread , threadID:3 exit thread , threadID:4 exit thread , threadID:2 exit thread , threadID:5 exit thread , threadID:6Process finished with exit code 0往期回顧
C++多線程快速入門(四)shared_mutex以及讀寫鎖應(yīng)用
C++多線程快速入門(三):生產(chǎn)者消費者模型與條件變量使用
C++多線程快速入門(二)共享數(shù)據(jù)同步以及數(shù)據(jù)競爭
C++多線程快速入門(一):基本&常用操作
總結(jié)
以上是生活随笔為你收集整理的C++多线程快速入门(五)简单线程池设计的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 驻马店做输卵管手术最好的医院推荐
- 下一篇: C++网络编程快速入门(一):TCP网络