一、線程池簡介
一個線程池是由若干在等待任務的線程組成的線程池,當請求到來時,將任務分配給其中一個空閑線程執行;當任務執行完畢後,線程並沒有結束,而是繼續等待下一個任務。在伺服器程序中,很多請求都是短時間的,大部分處理時間卻是在等待數據的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
微信掃一掃
支付寶掃一掃