一、線程池簡介
一個線程池是由若干在等待任務的線程組成的線程池,當請求到來時,將任務分配給其中一個空閑線程執行;當任務執行完畢後,線程並沒有結束,而是繼續等待下一個任務。在伺服器程序中,很多請求都是短時間的,大部分處理時間卻是在等待數據的IO操作上,因此線程池可以極大地提高伺服器的並發能力和響應速度。
二、C++線程池實現原理
1. 首先,我們需要引入常見的C++並發庫,如<mutex>
和<thread>
等。
#include <mutex> #include <thread>
2. 聲明一個線程池類ThreadPool。
class ThreadPool { public: //聲明構造函數、析構函數、添加任務函數等 private: //聲明任務隊列、線程池等變數 };
3. 在構造函數中,初始化線程池和任務隊列。
ThreadPool::ThreadPool(int size) { for (int i = 0; i < size; i++) { //創建線程,將線程函數設置為work函數 //存儲線程到線程池中 //設置線程為detachable,即自動釋放 } }
4. 添加任務函數需要將任務加入任務隊列,喚醒等待線程,通知有新的任務需要執行。
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; //將任務和返回值類型build成packaged_task auto task = std::make_shared<std::packaged_task<return_type()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...)); //使用future獲取非同步返回值 std::future<return_type> res = task->get_future(); { //加鎖保證對任務隊列的操作是原子的 std::unique_lock<std::mutex> lock(queue_mutex); //將任務加入隊列 tasks.emplace([task]() { (*task)(); }); } //喚醒等待線程,通知有新的任務需要執行 condition.notify_one(); return res; }
三、C++線程池實現代碼示例
下面是ThreadPool類的完整代碼示例:
#include <iostream> #include <vector> #include <queue> #include <thread> #include <mutex> #include <condition_variable> #include <future> #include <functional> class ThreadPool { public: //構造函數,初始化線程池和任務隊列 ThreadPool(int size) { for (int i = 0; i < size; i++) { threads.emplace_back(std::thread(&ThreadPool::work, this)); threads.back().detach(); } } //析構函數,回收線程池 ~ThreadPool() {} //添加任務函數,將任務加入任務隊列,喚醒等待線程,通知有新的任務需要執行 template <class F, class... Args> auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type> { //獲取任務返回值類型 using return_type = typename std::result_of<F(Args...)>::type; //將任務和返回值類型build成packaged_task auto task = std::make_shared<std::packaged_task<return_type()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...)); //使用future獲取非同步返回值 std::future<return_type> res = task->get_future(); { //加鎖保證對任務隊列的操作是原子的 std::unique_lock<std::mutex> lock(queue_mutex); //將任務加入隊列 tasks.emplace([task]() { (*task)(); }); } //喚醒等待線程,通知有新的任務需要執行 condition.notify_one(); return res; } private: //執行任務函數 void work() { while (true) { std::function<void()> task; { //加鎖保證對任務隊列的操作是原子的 std::unique_lock<std::mutex> lock(queue_mutex); //等待任務隊列非空 condition.wait(lock, [this]() { return !tasks.empty(); }); //取出隊列中的一個任務 task = std::move(tasks.front()); tasks.pop(); } //執行任務 task(); } } private: //線程池 std::vector<std::thread> threads; //任務隊列 std::queue<std::function<void()>> tasks; //隊列鎖 std::mutex queue_mutex; //任務隊列非空條件變數 std::condition_variable condition; }
四、線程池實現應用場景
線程池適用於很多需要處理大量短時間任務的場景,比如網路伺服器、圖像處理、視頻處理等。一些大型框架,如Web伺服器或消息匯流排系統,會使用線程池來處理並發請求,這樣可以大大提高響應速度和擴展能力。
五、總結
通過C++線程池實現,我們可以實現多線程任務的快速處理,提高系統的並發處理能力和響應速度,並且保證線程的可控性、執行流程的正確性和程序的高效性。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/198642.html