threadpool github線程池學習

參考項目

https://github.com/progschj/ThreadPool

源碼分析

// 常規頭文件保護宏, 避免重復 include
#ifndef THREAD_POOL_H
#define THREAD_POOL_H// 線程池, 存儲線程對象;
#include <vector>// 任務隊列, 雙向都可操作隊列, queue 不能刪除首個元素
#include <queue>// 智能指針
#include <memory>// c++11 線程對象
#include <thread>// 鎖保護隊列多線程任務添加, 刪除的安全;
#include <mutex>// 條件變量用來 condition wait 和 notify; 即事件的通知和阻塞等待
#include <condition_variable>// future 用來獲取更友好的封裝任務(函數), 并獲取返回值;
#include <future>// function 任務隊列
#include <functional>// 非法場景拋出異常
#include <stdexcept>// 為什么不用模板? 因為 enqueue 是模板, 可以兼容幾乎所有場景;
class ThreadPool {
public:// 設置線程池大小ThreadPool(size_t);// 添加函數, function 和 argstemplate<class F, class... Args>auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type>;// 吸狗函數~ThreadPool();
private:// need to keep track of threads so we can join themstd::vector< std::thread > workers;// the task queuestd::queue< std::function<void()> > tasks;// synchronizationstd::mutex queue_mutex;std::condition_variable condition;bool stop;
};// the constructor just launches some amount of workers
inline ThreadPool::ThreadPool(size_t threads):   stop(false)
{for(size_t i = 0;i<threads;++i)// 添加任務, 用 emplace_back 的形勢, 避免某些類型不支持拷貝;workers.emplace_back(// lambda 捕獲 this 對象, 用于操作任務隊列;[this]{// 死循環等待任務for(;;){// 任務獲取 void() 類型 統一封裝, 后面用 packaged_task 封裝不同的std::function<void()> task;{// 構建對象用于 conditionstd::unique_lock<std::mutex> lock(this->queue_mutex);// 等待線程池停止, 或者有任務;this->condition.wait(lock, [this]{ return this->stop || !this->tasks.empty(); });// 如果有任務 則 false, 即使停止也需要執行完任務之后再停止隊列// 如果請求停止, 且沒有任務,則終止;if(this->stop && this->tasks.empty())return;// 獲取第一個任務;task = std::move(this->tasks.front());this->tasks.pop();}// 執行獲取到任務;task();}});
}// add new work item to the pool
template<class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type>
{// 模板獲取函數返回值類型using return_type = typename std::result_of<F(Args...)>::type;// 將對象通過 bind 打包成可調用對象, 并封裝到 packeaged_task;auto task = std::make_shared< std::packaged_task<return_type()> >(std::bind(std::forward<F>(f), std::forward<Args>(args)...));// 生成獲取函數返回值的具柄對象;std::future<return_type> res = task->get_future();{// 加鎖添加元素;std::unique_lock<std::mutex> lock(queue_mutex);// don't allow enqueueing after stopping the poolif(stop)throw std::runtime_error("enqueue on stopped ThreadPool");// 用 lambda 再封裝是為了統一函數格式  void()// task 是 shared_ptr, 避免拷貝;tasks.emplace([task](){ (*task)(); });}// 提醒阻塞線程有新的任務;condition.notify_one();// 返回獲取函數返回值的具柄, 這樣可以獲取返回值;return res;
}// the destructor joins all threads
inline ThreadPool::~ThreadPool()
{{// 加鎖請求停止std::unique_lock<std::mutex> lock(queue_mutex);stop = true;}// 提醒所有阻塞線程, 需要停止線程池condition.notify_all();// join每個 thread 對象; 可以用 std::future 來作為 thread 對象, 讓 std 管理生命周期;// 除非開發者有更加細致的管理, 如 優先級, 棧, 添加屬性之類的操作;for(std::thread &worker: workers)worker.join();
}#endif

使用案例一

// create thread pool with 4 worker threads
ThreadPool pool(4);// enqueue and store future
auto result = pool.enqueue([](int answer) { return answer; }, 42);// get result from future
std::cout << result.get() << std::endl;

使用案例二

#include <iostream>
#include <vector>
#include <chrono>#include "ThreadPool.h"int main()
{ThreadPool pool(4);std::vector< std::future<int> > results;for(int i = 0; i < 8; ++i) {results.emplace_back(pool.enqueue([i] {std::cout << "hello " << i << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));std::cout << "world " << i << std::endl;return i*i;}));}for(auto && result: results)std::cout << result.get() << ' ';std::cout << std::endl;return 0;
}

無注釋版本

#ifndef THREAD_POOL_H
#define THREAD_POOL_H#include <vector>
#include <queue>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>
#include <stdexcept>class ThreadPool {
public:ThreadPool(size_t);template<class F, class... Args>auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type>;~ThreadPool();
private:// need to keep track of threads so we can join themstd::vector< std::thread > workers;// the task queuestd::queue< std::function<void()> > tasks;// synchronizationstd::mutex queue_mutex;std::condition_variable condition;bool stop;
};// the constructor just launches some amount of workers
inline ThreadPool::ThreadPool(size_t threads):   stop(false)
{for(size_t i = 0;i<threads;++i)workers.emplace_back([this]{for(;;){std::function<void()> task;{std::unique_lock<std::mutex> lock(this->queue_mutex);this->condition.wait(lock,[this]{ return this->stop || !this->tasks.empty(); });if(this->stop && this->tasks.empty())return;task = std::move(this->tasks.front());this->tasks.pop();}task();}});
}// add new work item to the pool
template<class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type>
{using return_type = typename std::result_of<F(Args...)>::type;auto task = std::make_shared< std::packaged_task<return_type()> >(std::bind(std::forward<F>(f), std::forward<Args>(args)...));std::future<return_type> res = task->get_future();{std::unique_lock<std::mutex> lock(queue_mutex);// don't allow enqueueing after stopping the poolif(stop)throw std::runtime_error("enqueue on stopped ThreadPool");tasks.emplace([task](){ (*task)(); });}condition.notify_one();return res;
}// the destructor joins all threads
inline ThreadPool::~ThreadPool()
{{std::unique_lock<std::mutex> lock(queue_mutex);stop = true;}condition.notify_all();for(std::thread &worker: workers)worker.join();
}#endif

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

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

相關文章

微信小程序制作-背單詞的小程序制作

微信小程序–背單詞的 好久沒有發過文章了&#xff0c;但是不代表著我不去學習了嘍&#xff0c;以下是我最近做的東西&#xff0c;前端的UI由朋友設計的&#xff0c;目前這個是前端使用的是微信小程序后端是Python的一個輕量型框架&#xff0c;FastApi&#xff0c;嗯&#xff…

MyBatis 四大核心組件之 Executor 源碼解析

&#x1f680; 作者主頁&#xff1a; 有來技術 &#x1f525; 開源項目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 倉庫主頁&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 歡迎點贊…

List 接口

1 List 接口 java.util 中的集合類包含 Java 中某些最常用的類。最常用的集合類是 List 和 Map。 List是一種常用的集合類型&#xff0c;它可以存儲任意類型的對象&#xff0c;也可以結合泛型來存儲具體的類型對象&#xff0c;本質上就是一個容器。 1.1 List 類型介紹 有序性…

06-React組件 Redux React-Redux

React組件化&#xff08;以Ant-Design為例&#xff09; 組件化編程&#xff0c;只需要去安裝好對應的組件&#xff0c;然后通過各式各樣的組件引入&#xff0c;實現快速開發 我們這里學習的是 Ant-design &#xff08;應該是這樣&#xff09;&#xff0c;它有很多的組件供我們…

計算機網絡測試題第二部分

前言:如果沒有做在線測試請自主獨立完成&#xff0c;本篇文章只作為學習計算機網絡的參考&#xff0c;題庫中的題存在一定錯誤和不完整&#xff0c;請學習時&#xff0c;查找多方書籍論證&#xff0c;獨立思考&#xff0c;如果存在疑慮可以評論區討論。查看時&#xff0c;請分清…

pytorch debug 常用工具

自動辨識圖像格式可視化 import numpy as np import matplotlib.pyplot as plt from PIL import Imagedef convert_to_numpy(image_input):"""自動檢測輸入圖像類型&#xff0c;并將其轉換為NumPy數組。"""if isinstance(image_input, np.ndarr…

7-3 Left-pad

根據新浪微博上的消息&#xff0c;有一位開發者不滿NPM&#xff08;Node Package Manager&#xff09;的做法&#xff0c;收回了自己的開源代碼&#xff0c;其中包括一個叫left-pad的模塊&#xff0c;就是這個模塊把javascript里面的React/Babel干癱瘓了。這是個什么樣的模塊&a…

物聯網IC

物聯網IC 電子元器件百科 文章目錄 物聯網IC前言一、物聯網IC是什么二、物聯網IC的類別三、物聯網IC的應用實例四、物聯網IC的作用原理總結前言 物聯網IC的功能和特性可以根據不同的物聯網應用需求來選擇和配置,以滿足物聯網設備在連接、通信、感知和控制方面的需求。 一、物…

猜數字游戲Ⅱ

你和朋友一起玩猜數字游戲&#xff0c;你寫出一個秘密數字&#xff0c;請朋友猜這個數字是多少。朋友每猜測一次&#xff0c;你就會給他一個包含下述信息的提示&#xff1a; 猜測數字中有多少位屬于數字和確切位置都猜對了&#xff08;稱為 "Bulls"&#xff0c;公牛&…

VOL-vue 框架 文件上傳控件關于大文件上傳等待的修改

我的項目在測試voltable列表組件中對阿里云OSS做附件上傳時&#xff0c;幾十M的文件可能就會需要一段時間來上傳&#xff0c;才能有OSS的狀態和鏈接返回。 但是控件VolUpload.vue并沒有去在這方面做任何交互體驗上的控制&#xff0c;而且VolUpload.vue本身寫的幾個上傳函數都是…

SpringBoo在項目停止(服務停止/關閉退出)之后執行的方法

SpringBoo在項目停止/服務停止/關閉退出之后執行的方法 1.實現DisposableBean接口2.使用PreDestroy注解 SpringApplication會向JVM注冊一個關閉鉤子(hook)&#xff0c;以確保ApplicationContext在退出時正常關閉。 可以使用所有標準的Spring生命周期回調&#xff08;例如Dispos…

內測分發是什么?十年的前端開發者帶你了解

內測分發是軟件開發過程中的一個階段&#xff0c;特別指軟件還未完全完成或準備對外廣泛發布前&#xff0c;向一定范圍的用戶群體提供該軟件版本的測試機會&#xff0c;以便收集反饋和修復潛在的問題。在講解內測分發之前&#xff0c;我們需要明確幾個相關概念&#xff1a; 軟件…

區塊鏈媒體宣發:揭示優勢與趨勢,引領信息傳播新時代

在數字化潮流中&#xff0c;區塊鏈技術正以驚人的速度改變著傳媒行業的格局。從區塊鏈媒體宣發中獲得的種種優勢和未來的趨勢&#xff0c;不僅為企業帶來了新的推廣途徑&#xff0c;也在信息傳播領域掀起了一場革命。本文將深入探討區塊鏈媒體宣發的優勢以及未來的發展趨勢。 1…

排序算法---選擇排序

1.實現流程&#xff1a; 1. 把第一個沒有排序過的元素設置為最小值&#xff1b; 2. 遍歷每個沒有排序過的元素&#xff1b; 3. 如果元素 < 現在的最小值&#xff1b; 4. 將此元素設置成為新的最小值&#xff1b; 5. 將最小值和第一個沒有排序過的位置交換 選擇排序執行流程…

初識Ceph --組件、存儲類型、存儲原理

目錄 ceph組件存儲類型塊存儲文件存儲對象存儲 存儲過程 ceph Ceph&#xff08;分布式存儲系統&#xff09;是一個開源的分布式存儲系統&#xff0c;設計用于提供高性能、高可靠性和可擴展性的存儲服務&#xff0c;可以避免單點故障&#xff0c;支持塊存儲、對象存儲以及文件系…

【小白專用】Apache2.4+PHP8.3+MYSQL的配置

1.下載PHP和Apache 1、PHP下載 PHP For Windows: Binaries and sources Releases 注意&#xff1a; 1.使用Apache作為服務器的話&#xff0c;一定要下載Thread Safe的&#xff0c;否則沒有php8apache2_4.dll這個文件&#xff0c; 如果使用IIS的請下載 NON Tread safe的 2.如果…

USB連接器

USB連接器 電子元器件百科 文章目錄 USB連接器前言一、USB連接器是什么二、USB連接器的類別三、USB連接器的應用實例四、USB連接器的作用原理總結前言 USB連接器的使用廣泛,幾乎所有現代電子設備都具備USB接口,使得設備之間的數據傳輸和充電變得簡單和便捷。 一、USB連接器是…

element-ui按鈕el-button,點擊之后恢復之前的顏色

在開發過程中, 使用el-button 按鈕點擊之后, 沒有恢復到之前的顏色, 還是保持點擊之后的顏色,需要解決這個問題, <template><div><el-button size"mini" type"primary" plain click"onClick($event)">按鈕</el-button>…

iOS按鈕控件UIButton使用

1.在故事板中添加按鈕控件,步聚如下: 同時按鈕Shift+Commad+L在出現在控件庫中選擇Button并拖入View Controller Scene中 將控件與變量btnSelect關聯 關聯后空心變實心 如何關聯?直接到屬性窗口拖按鈕變量到控件上,出現一條線,然后松開,這樣就關聯成功了 關聯成功后屬性窗口…

LinuxBasicsForHackers筆記 -- 了解和檢查無線網絡

無線網絡 AP (access point) – 無線用戶連接以訪問互聯網的設備。SSID (service set identifier) – 網絡的名稱。ESSID (extended service set identifier) – 與 SSID 相同&#xff0c;但它可用于無線 LAN 中的多個 AP。BSSID (basic service set identifier) – 每個AP的唯…