C++ 學習筆記實戰(zhàn)寫一個簡單的線程池示例
更新時間:2023年10月29日 15:57:16 作者:Totn
這篇文章主要為大家介紹了C++實現(xiàn)一個簡單的線程池學習實戰(zhàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
線程池的工作原理
- 在構造函數(shù)中,創(chuàng)建指定數(shù)量的工作線程,并將它們存儲在
workers
向量中。 - 每個工作線程都通過無限循環(huán)來執(zhí)行任務隊列中的任務。
- 設置一個
public
函數(shù),接收新任務,封裝為std::function<void()>
并添加到任務隊列中。 - 等待的工作線程會被喚醒并獲取任務執(zhí)行,直到線程池被銷毀或調(diào)用
stop()
函數(shù)停止。
第一步, 創(chuàng)建指定數(shù)量的工作線程
class ThreadPool { public: ThreadPool(int num){ // 啟動指定數(shù)量的線程 for(int i = 0; i < num; i++ ) { // 使用循環(huán)創(chuàng)建指定數(shù)量的工作線程。每個工作線程都是通過`emplace_back`函數(shù)向`workers`容器中添加一個lambda函數(shù)創(chuàng)建的 // 添加一個lambda函數(shù)即為創(chuàng)建一個線程 workers.emplace_back([this]{ // code... }); } } private: // 用向量儲存線程 std::vector<std::thread> workers; }
第二步在每個線程中啟動死循環(huán),依次從任務隊列中取中任務,直到隊列為空或設置stop
標識為true;
第二步,在第一步基礎上,添加代碼
class ThreadPool { public: ThreadPool(int num): stoped(false) { // 啟動指定數(shù)量的線程 for(int i = 0; i < num; i++ ) { // 使用循環(huán)創(chuàng)建指定數(shù)量的工作線程。每個工作線程都是通過`emplace_back`函數(shù)向`workers`容器中添加一個lambda函數(shù)創(chuàng)建的 // 添加一個lambda函數(shù)即為創(chuàng)建一個線程 workers.emplace_back([this]{ // 死循環(huán) while(true) { // 設置一個task接收從隊列中取出的任務 std::function<void()> task; { // 從隊列中取任務要加鎖,以避免重復讀 std::unique_lock<std::mutex> lock(ququeMutex); // 如果stoped==true,或任務不為空,則使當前線程等待 condition.wait(lock, [this]{ return stroped || !tasks.empty(); }); // 設置stoped為true后,則等到任務都完成為退出(tasks任務隊列為空) if (stoped && tasks.empty()) { return; } // 從隊列中接收任務 task = std::move(tasks.front()); // 彈出已經(jīng)接收的任務 tasks.pop(); } // 以上代碼使用{}限制了作用域,在域內(nèi)啟用的鎖queueMutex在域結束后自動解鎖 } }); } } // 設置停止標識 void stop() { std::unique_lock<std::mutex> lock(queueMutex); stoped = true; } private: // 用向量儲存線程 std::vector<std::thread> workers; // 工作隊列 std::queue<std::function<void()> tasks; // 隊列互斥鎖 std::mutex queueMutex; // 條件變量 std::condition_variable condition; // stop標識 bool stoped; }
第三步,設置一個函數(shù)用從外部接收任務
// class ThreadBool... template<class F> void enqueue(F&& f){ { // 在域內(nèi)啟用鎖, 保證加任務時沒沖突 std::unique_lock<std::mutex> lock(queueMutex); // 轉發(fā)任務到tasks隊列中 tasks.emplace(std::forword<F>(f)); } // 通知一個線程起來接活 condition.notify_one(); } // ...
第四步,設置析構函數(shù)等待所有線程執(zhí)行完成
// class ThreadBool ~ThreadPool(){ ?。? std::unique_lock<std::mutex> lock(queueMutex); stoded = true; } // 阻塞等待所有線程 for(std::thread& worker: workers){ worker.join(); } }
最后完整代碼
#include <vector> #include <thread> #include <queue> #include <mutex> #include <condition_variable> #include <functional> #include <iostream> thread_local int thr_num; class Task{ public run(int num = 0) { thr_num = num; std::cout << "當前任務號是" << thr_num << std::endl; } } class ThreadPool { public: ThreadPool(int num): stoped(false) { // 啟動指定數(shù)量的線程 for(int i = 0; i < num; i++ ) { // 使用循環(huán)創(chuàng)建指定數(shù)量的工作線程。每個工作線程都是通過`emplace_back`函數(shù)向`workers`容器中添加一個lambda函數(shù)創(chuàng)建的 // 添加一個lambda函數(shù)即為創(chuàng)建一個線程 workers.emplace_back([this]{ // 死循環(huán) while(true) { // 設置一個task接收從隊列中取出的任務 std::function<void()> task; { // 從隊列中取任務要加鎖,以避免重復讀 std::unique_lock<std::mutex> lock(ququeMutex); // 如果stoped==true,或任務不為空,則使當前線程等待 condition.wait(lock, [this]{ return stroped || !tasks.empty(); }); // 設置stoped為true后,則等到任務都完成為退出(tasks任務隊列為空) if (stoped && tasks.empty()) { return; } // 從隊列中接收任務 task = std::move(tasks.front()); // 彈出已經(jīng)接收的任務 tasks.pop(); } // 以上代碼使用{}限制了作用域,在域內(nèi)啟用的鎖queueMutex在域結束后自動解鎖 } }); } } // 設置停止標識 void stop() { std::unique_lock(std::mutex ) stoped = true; } private: // 用向量儲存線程 std::vector<std::thread> workers; // 工作隊列 std::queue<std::function<void()> tasks; // 隊列互斥鎖 std::mutex queueMutex; // 條件變量 std::condition_variable condition; // stop標識 bool stoped; } int main() { ThreadPool tp(4); Task task; for(int i = 0; i<4; i++) { int num = i; tp.enqueue([num, &task] { task.run(num); }); } return 0; }
以上就是C++ 學習筆記實戰(zhàn)寫一個簡單的線程池示例的詳細內(nèi)容,更多關于C++ 線程池的資料請關注腳本之家其它相關文章!