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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++多线程快速入门(五)简单线程池设计

發(fā)布時間:2023/12/1 c/c++ 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++多线程快速入门(五)简单线程池设计 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

目錄

  • 設(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)造出來的每個線程在干啥:
while(true) {{上鎖,訪問任務(wù)隊列// 注意由于隊列本身是個多線程共享資源,所以對于隊列取元素以及狀態(tài)判斷都是要先加鎖再操作隊列為空則一直循環(huán) // 為什么要用循環(huán)判斷呢?// 這是因為wait()從阻塞到返回,不一定就是由于notify_one()函數(shù)造成的,還有可能由于系統(tǒng)的不確定原因喚醒(可能和條件變量的實現(xiàn)機制有關(guān)),這個的時機和頻率都是不確定的,被稱作偽喚醒,如果在錯誤的時候被喚醒了,執(zhí)行后面的語句就會錯誤,所以需要再次判斷隊列是否為空,如果還是為空,就繼續(xù)wait()阻塞。{如果m_bRunning為false,說明此時應(yīng)該中止線程操作,所以需要連著跳出兩個循環(huán),所以直接用goto label吧否則就一直等待在這兒,wait()可以讓線程陷入休眠狀態(tài),在消費者生產(chǎn)者模型中,如果生產(chǎn)者發(fā)現(xiàn)隊列中沒有東西,就可以讓自己休眠.}此時 獲取隊頭元素,并將隊頭元素出隊}// 為了減少鎖的粒度,接下來的操作不需要加鎖了,因為已經(jīng)拿到了隊列中的元素執(zhí)行Task對象的doIt()方法,也就是打印任務(wù)id和線程id } label : 打印當前線程id

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)容,希望文章能夠幫你解決所遇到的問題。

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