高階開發基礎——快速入門C++并發編程6——大作業:實現一個超級迷你的線程池

目錄

實現一個無返回的線程池

完全代碼實現

Reference


實現一個無返回的線程池

實現一個簡單的線程池非常簡單,我們首先聊一聊線程池的定義:

線程池(Thread Pool) 是一種并發編程的設計模式,用于管理和復用多個線程,以提高程序的性能和資源利用率。它的核心思想是預先創建一組線程,并將任務分配給這些線程執行,而不是為每個任務單獨創建和銷毀線程。線程池廣泛應用于需要處理大量短期任務的場景,例如 Web 服務器、數據庫連接池、任務調度系統等。換而言之,線程池說白了就是一種餓漢思維——直接預先提供若干的線程,由線程池內部控制調度,確保我們可以只關心任務的提交以及完成。

我們下面要做的是設計一個任務是不返回的線程池。所以,我們約束我們的函數是:

using supportive_task_type = std::function<void()>;

下一步,就是構造我們的線程池的線程。注意的是——線程和任務是解耦合的,意味著我們需要一個中間函數解耦合任務派發。筆者決定,將任務派發分到一個私有函數完成:

 ?  CCThreadPool(const int workers_num) {for(int i = 0; i < workers_num; i++){internal_threads.emplace_back([this](){__scheduled();});}}

上面這個代碼很簡單,就是將每一個線程都分配一個調度函數,這個調度函數來委派分發任務,辦法說簡單也很簡單:

void __scheduled(){while(1){// sources protectionsstd::unique_lock<std::mutex> locker(internal_mutex);// waiting for the access of the task resourcescontrolling_cv.wait(locker, [this]{return thread_pool_status || !tasks_queue.empty();});// quit if requriedif(thread_pool_status && tasks_queue.empty()){return;}// 現在我們可以取到任務執行了supportive_task_type task(std::move(tasks_queue.front()));tasks_queue.pop();locker.unlock();task();}}

當析構的時候,我們也要通知所有線程的cv不要睡眠了,由于設置了thread_pool_status是true,直接線程跳出來結束全文。

 ?  ~CCThreadPool(){thread_pool_status = true;controlling_cv.notify_all();for(auto& thread : internal_threads){thread.join();}}

完全代碼實現

#include <condition_variable>
#include <functional>
#include <mutex>
#include <print>
#include <queue>
#include <thread>
#include <utility>
#include <vector>
?
class CCThreadPool {public:CCThreadPool() ? ? ? ? ? ? ? ? ? ? ? ?  = delete;CCThreadPool(const CCThreadPool &) ? ?  = delete;CCThreadPool &operator=(CCThreadPool &) = delete;
?CCThreadPool(const int workers_num) {for(int i = 0; i < workers_num; i++){internal_threads.emplace_back([this](){__scheduled();});}}
?~CCThreadPool(){thread_pool_status = true;controlling_cv.notify_all();for(auto& thread : internal_threads){thread.join();}}
?template<typename F, typename... Args>void enTask(F&& f, Args&&... args){supportive_task_type task(std::bind(std::forward<F&&>(f), std::forward<Args&&>(args)...));{std::unique_lock<std::mutex> locker(internal_mutex);tasks_queue.emplace(std::move(task));}controlling_cv.notify_one();}
?private:void __scheduled(){while(1){std::unique_lock<std::mutex> locker(internal_mutex);controlling_cv.wait(locker, [this]{return thread_pool_status || !tasks_queue.empty();});// quitif(thread_pool_status && tasks_queue.empty()){return;}supportive_task_type task(std::move(tasks_queue.front()));tasks_queue.pop();locker.unlock();task();}}
?using supportive_task_type = std::function<void()>;std::vector<std::thread> internal_threads;std::queue<supportive_task_type> tasks_queue;std::mutex internal_mutex;std::condition_variable controlling_cv;bool thread_pool_status = false;
};
?
?
int main()
{std::println("Task start");CCThreadPool pool(4);for (int i = 0; i < 8; ++i) {pool.enTask([i] {std::println("Task {} is started at thread with id {}", i, std::this_thread::get_id());std::this_thread::sleep_for(std::chrono::seconds(1));std::println("Task {} is done", i);});}return 0;
}

Reference

8. C++11 跨平臺線程池-See的編程日記 (seestudy.cn)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/894578.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/894578.shtml
英文地址,請注明出處:http://en.pswp.cn/news/894578.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

pytorch實現主成分分析 (PCA):用于數據降維和特征提取

人工智能例子匯總&#xff1a;AI常見的算法和例子-CSDN博客 使用 PyTorch 實現主成分分析&#xff08;PCA&#xff09;可以通過以下步驟進行&#xff1a; 標準化數據&#xff1a;首先&#xff0c;需要對數據進行標準化處理&#xff0c;確保每個特征的均值為 0&#xff0c;方差…

100 ,【8】 buuctf web [藍帽杯 2021]One Pointer PHP(別看)

進入靶場 沒提示&#xff0c;去看源代碼。 user.php <?php // 定義一個名為 User 的類&#xff0c;該類可用于表示用戶相關信息或執行與用戶有關的操作 class User{// 聲明一個公共屬性 $count&#xff0c;可在類的內部和外部直接訪問// 這個屬性可能用于記錄與用戶相關…

巧妙利用數據結構優化部門查詢

目錄 一、出現的問題 部門樹接口超時 二、問題分析 源代碼分析 三、解決方案 具體實現思路 四、優化的效果 一、出現的問題 部門樹接口超時 無論是在A項目還是在B項目中&#xff0c;都存在類似的頁面&#xff0c;其實就是一個部門列表或者叫組織列表。 從頁面的展示形式…

QT簡單實現驗證碼(字符)

0&#xff09; 運行結果 1&#xff09; 生成隨機字符串 Qt主要通過QRandomGenerator類來生成隨機數。在此之前的版本中&#xff0c;qrand()函數也常被使用&#xff0c;但從Qt 5.10起&#xff0c;推薦使用更現代化的QRandomGenerator類。 在頭文件添加void generateRandomNumb…

JavaFX - 3D 形狀

在前面的章節中&#xff0c;我們已經了解了如何在 JavaFX 應用程序中的 XY 平面上繪制 2D 形狀。除了這些 2D 形狀之外&#xff0c;我們還可以使用 JavaFX 繪制其他幾個 3D 形狀。 通常&#xff0c;3D 形狀是可以在 XYZ 平面上繪制的幾何圖形。它們由兩個或多個維度定義&#…

深入理解開放尋址法中的三種探測序列

一、引言 開放尋址法是解決散列表中沖突的一種重要方法&#xff0c;當發生沖突&#xff08;即兩個不同的鍵通過散列函數計算得到相同的散列值&#xff09;時&#xff0c;它會在散列表中尋找下一個可用的存儲位置。而探測序列就是用于確定在發生沖突后&#xff0c;依次嘗試哪些…

【雙指針題目】

雙指針 美麗區間&#xff08;滑動窗口&#xff09;合并數列&#xff08;雙指針的應用&#xff09;等腰三角形全部所有的子序列 美麗區間&#xff08;滑動窗口&#xff09; 美麗區間 滑動窗口模板&#xff1a; int left 0, right 0;while (right < nums.size()) {// 增大…

為什么命令“echo -e “\033[9;0]“ > /dev/tty0“能控制開發板上的LCD不熄屏?

為什么命令"echo -e “\033[9;0]” > /dev/tty0"能控制開發板上的LCD不熄屏&#xff1f; 在回答這個問題前請先閱讀我之前寫的與tty和終端有關的博文 https://blog.csdn.net/wenhao_ir/article/details/145431655 然后再來看這條命令的解釋就要容易些了。 這條…

嵌入式八股文面試題(一)C語言部分

1. 變量/函數的聲明和定義的區別&#xff1f; &#xff08;1&#xff09;變量 定義不僅告知編譯器變量的類型和名字&#xff0c;還會分配內存空間。 int x 10; // 定義并初始化x int x; //同樣是定義 聲明只是告訴編譯器變量的名字和類型&#xff0c;但并不為它分配內存空間…

go-zero學習筆記(三)

利用goctl生成rpc服務 編寫proto文件 // 聲明 proto 使用的語法版本 syntax "proto3";// proto 包名 package demoRpc;// golang 包名(可選) option go_package "./demo";// 如需為 .proto 文件添加注釋&#xff0c;請使用 C/C 樣式的 // 和 /* ... */…

Javascript代碼庫-jQuery入門

摘自千鋒教育kerwin的js教程 jQuery 是一個前端庫&#xff0c;也是一個方法庫他里面封裝著一些列的方法供我們使用我們常用的一些方法它里面都有&#xff0c;我們可以直接拿來使用就行了jQuery 之所以好用&#xff0c;很多人愿意使用&#xff0c;是因為他的幾個優點太強大了 優…

【25考研】南開軟件考研復試復習重點!

一、復試內容 復試采取現場復試的方式。復試分為筆試、機試和面試三部分。三部分合計100分&#xff0c;其中筆試成績占30%、機試成績占30%、面試成績占40%。 1.筆試&#xff1a;專業綜合基礎測試 考核方式&#xff1a;閉卷考試&#xff0c;時長為90分鐘。 筆試考查內容范圍…

【最長上升子序列Ⅱ——樹狀數組,二分+DP,純DP】

題目 代碼&#xff08;只給出樹狀數組的&#xff09; #include <bits/stdc.h> using namespace std; const int N 1e510; int n, m; int a[N], b[N], f[N], tr[N]; //f[i]表示以a[i]為尾的LIS的最大長度 void init() {sort(b1, bn1);m unique(b1, bn1) - b - 1;for(in…

012-51單片機CLD1602顯示萬年歷+鬧鐘+農歷+整點報時

1. 硬件設計 硬件是我自己設計的一個通用的51單片機開發平臺&#xff0c;可以根據需要自行焊接模塊&#xff0c;這是用立創EDA畫的一個雙層PCB板&#xff0c;所以模塊都是插針式&#xff0c;不是表貼的。電路原理圖在文末的鏈接里&#xff0c;PCB圖暫時不選擇開源。 B站上傳的…

容器迭代器iterator

文章目錄 1、自定義String實現iterator2、自定義vector實現iterator3、迭代器失效問題 迭代器的功能&#xff1a;提供一種統一的方式&#xff0c;來透明的遍歷容器。 迭代器可以透明的訪問容器內部的元素的值&#xff0c;而無需了解其底層遍歷機制具體是數組的下標還是鏈表的指…

對象的實例化、內存布局與訪問定位

一、創建對象的方式 二、創建對象的步驟: 一、判斷對象對應的類是否加載、鏈接、初始化: 虛擬機遇到一條new指令&#xff0c;首先去檢查這個指令的參數能否在Metaspace的常量池中定位到一個類的符號引用&#xff0c;并且檢查這個符號引用代表的類是否已經被加載、解析和初始化…

傳輸層協議 UDP 與 TCP

&#x1f308; 個人主頁&#xff1a;Zfox_ &#x1f525; 系列專欄&#xff1a;Linux 目錄 一&#xff1a;&#x1f525; 前置復盤&#x1f98b; 傳輸層&#x1f98b; 再談端口號&#x1f98b; 端口號范圍劃分&#x1f98b; 認識知名端口號 (Well-Know Port Number) 二&#xf…

實驗十一 Servlet(二)

實驗十一 Servlet(二) 【實驗目的】 1&#xff0e;了解Servlet運行原理 2&#xff0e;掌握Servlet實現方式 【實驗內容】 改造實驗10&#xff0c;引入數據庫&#xff0c;創建用戶表&#xff0c;包括用戶名和密碼&#xff1a;客戶端通過login.jsp發出登錄請求&#xff0c;請求…

服務SDK三方新版中央倉庫和私服發布詳解

預備信息Github倉庫發布Gradle版本匹配Gradle項目構建全局變量定義Gradle項目Nexus倉庫配置與發布過程Gradle項目發布至Sonatype中央倉庫配置過程總結當我們在實現一個項目技術總結、工具類封裝或SDK封裝,通常是為了方便開發者使用特定服務或平臺而提供的一組工具和API。您可能…

git 新項目

新項目git 新建的項目如何進行git 配置git git config --global user.name "cc" git config --global user.email ccexample.com配置遠程倉庫路徑 // 添加 git remote add origin http://gogs/cc/mc.git //如果配錯了&#xff0c;刪除 git remote remove origin初…