一、线程池简介
一个线程池是由若干在等待任务的线程组成的线程池,当请求到来时,将任务分配给其中一个空闲线程执行;当任务执行完毕后,线程并没有结束,而是继续等待下一个任务。在服务器程序中,很多请求都是短时间的,大部分处理时间却是在等待数据的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/n/198642.html
微信扫一扫
支付宝扫一扫