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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++实现一个线程池

發(fā)布時(shí)間:2023/12/16 c/c++ 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++实现一个线程池 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、為什么使用線程池

大家都知道C++支持多線程開發(fā),也就是支持多個(gè)任務(wù)并行運(yùn)行,我們也知道線程的生命周期中包括創(chuàng)建、就緒、運(yùn)行、阻塞、銷毀等階段,所以如果要執(zhí)行的任務(wù)很多,每個(gè)任務(wù)都需要一個(gè)線程的話,那么頻繁的創(chuàng)建、銷毀線程會(huì)比較耗性能。

有了線程池就不用創(chuàng)建更多的線程來完成任務(wù),它可以:

降低資源的消耗,通過重復(fù)利用已經(jīng)創(chuàng)建的線程降低線程創(chuàng)建和銷毀造成的消耗。

提高相應(yīng)速度,當(dāng)任務(wù)到達(dá)的時(shí)候,任務(wù)可以不需要等到線程創(chuàng)建就能立刻執(zhí)行。

提高線程的可管理性,線程是稀缺資源,使用線程池可以統(tǒng)一的分配、調(diào)優(yōu)和監(jiān)控。

二、線程池的原理

通俗的講,線程池就是一個(gè)線程集合,里面已經(jīng)提前創(chuàng)建好了若干個(gè)線程,當(dāng)需要線程的時(shí)候到線程集合里獲取一個(gè)即可,這樣省去了創(chuàng)建線程的時(shí)間,當(dāng)然也省去了系統(tǒng)回收線程的時(shí)間,當(dāng)線程池里的線程都被使用了后,只能阻塞等待了,等待獲取線程池后被釋放的線程。

當(dāng)線程池提交一個(gè)任務(wù)到線程池后,執(zhí)行流程如下:

線程池先判斷核心線程池里面的線程是否都在執(zhí)行任務(wù)。如果不是都在執(zhí)行任務(wù),則創(chuàng)建一個(gè)新的工作線程來執(zhí)行任務(wù)。如果核心線程池中的線程都在執(zhí)行任務(wù),則判斷工作隊(duì)列是否已滿。如果工作隊(duì)列沒有滿,則將新提交的任務(wù)存儲(chǔ)到這個(gè)工作隊(duì)列中,如果工作隊(duì)列滿了,線程池則判斷線程池的線程是否都處于工作狀態(tài)。如果沒有,則創(chuàng)建一個(gè)新的工作線程來執(zhí)行任務(wù)。如果已經(jīng)滿了,則交給飽和策略來處理 ,也就是拒接策略。
一句話:管理一個(gè)任務(wù)隊(duì)列,一個(gè)線程隊(duì)列,然后每次去一個(gè)任務(wù)分配給一個(gè)線程去做,循環(huán)往復(fù)。

三、代碼實(shí)現(xiàn)

有什么問題?線程池一般是要復(fù)用線程,所以如果是取一個(gè)task分配給某一個(gè)thread,執(zhí)行完之后再重新分配,在語言層面這是基本不能實(shí)現(xiàn)的:C++的thread都是執(zhí)行一個(gè)固定的task函數(shù),執(zhí)行完之后線程也就結(jié)束了。所以該如何實(shí)現(xiàn)task和thread的分配呢?

讓每一個(gè)thread創(chuàng)建后,就去執(zhí)行調(diào)度函數(shù):循環(huán)獲取task,然后執(zhí)行。

這個(gè)循環(huán)該什么時(shí)候停止呢?

很簡單,當(dāng)線程池停止使用時(shí),循環(huán)停止。

這樣一來,就保證了thread函數(shù)的唯一性,而且復(fù)用線程執(zhí)行task。

總結(jié)一下,我們的線程池的主要組成部分有二:

  • 任務(wù)隊(duì)列(Task Queue)
  • 線程池(Thread Pool)

#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); //構(gòu)造函數(shù)template<class F, class... Args> //類模板auto enqueue(F&& f, Args&&... args)->std::future<decltype(func(args...))>;//任務(wù)入隊(duì)~ThreadPool(); //析構(gòu)函數(shù)private:std::vector< std::thread > workers; //線程隊(duì)列,每個(gè)元素為一個(gè)Thread對(duì)象std::queue< std::function<void()> > tasks; //任務(wù)隊(duì)列,每個(gè)元素為一個(gè)函數(shù)對(duì)象 std::mutex queue_mutex; //互斥量std::condition_variable condition; //條件變量bool stop; //停止 };// 構(gòu)造函數(shù),把線程插入線程隊(duì)列,插入時(shí)調(diào)用embrace_back(),用匿名函數(shù)lambda初始化Thread對(duì)象 inline ThreadPool::ThreadPool(size_t threads) : stop(false){for(size_t i = 0; i<threads; ++i)workers.emplace_back([this]{for(;;){// task是一個(gè)函數(shù)類型,從任務(wù)隊(duì)列接收任務(wù)std::function<void()> task; {//給互斥量加鎖,鎖對(duì)象生命周期結(jié)束后自動(dòng)解鎖std::unique_lock<std::mutex> lock(this->queue_mutex);//(1)當(dāng)匿名函數(shù)返回false時(shí)才阻塞線程,阻塞時(shí)自動(dòng)釋放鎖。//(2)當(dāng)匿名函數(shù)返回true且受到通知時(shí)解阻塞,然后加鎖。this->condition.wait(lock,[this]{ return this->stop || !this->tasks.empty(); });if(this->stop && this->tasks.empty())return;//從任務(wù)隊(duì)列取出一個(gè)任務(wù)task = std::move(this->tasks.front());this->tasks.pop();} // 自動(dòng)解鎖task(); // 執(zhí)行這個(gè)任務(wù)}}); }// 添加新的任務(wù)到任務(wù)隊(duì)列 template<class F, class... Args> auto ThreadPool::enqueue(F&& f, Args&&... args)->std::future<decltype(func(args...))> {// 獲取函數(shù)返回值類型 using return_type = decltype(func(args...));// 創(chuàng)建一個(gè)指向任務(wù)的智能指針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); //加鎖if(stop)throw std::runtime_error("enqueue on stopped ThreadPool");tasks.emplace([task](){ (*task)(); }); //把任務(wù)加入隊(duì)列} //自動(dòng)解鎖condition.notify_one(); //通知條件變量,喚醒一個(gè)線程return res; }// 析構(gòu)函數(shù),刪除所有線程 inline ThreadPool::~ThreadPool() {{std::unique_lock<std::mutex> lock(queue_mutex);stop = true;}condition.notify_all();for(std::thread &worker: workers)worker.join(); }#endif

使用

#include <iostream> #include <chrono> #include "ThreadPool.h"void func() {std::this_thread::sleep_for(std::chrono::milliseconds(100));std::cout<<"worker thread ID:"<<std::this_thread::get_id()<<std::endl; }int main() {ThreadPool pool(4);while(1){pool.enqueue(func);} }

打印

?

參考:

基于C++11實(shí)現(xiàn)線程池 - 知乎

C++實(shí)現(xiàn)線程池_蓬萊道人的博客-CSDN博客_c++ 線程池

C++實(shí)現(xiàn)線程池_曉楓寒葉的博客-CSDN博客_c++ 線程池
C++17future類+可變參模板實(shí)現(xiàn)線程池_剛?cè)腴T的代碼spa技師的博客-CSDN博客_c++17 可變參

總結(jié)

以上是生活随笔為你收集整理的C++实现一个线程池的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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