线程池是什么
线程池是一种用于管理和复用一组线程的设计模式,旨在提高多线程程序的性能和资源利用率。线程池通过预先创建一定数量的线程,并将任务分配给这些线程执行,避免了频繁创建和销毁线程的开销。
线程池的主要优点包括:
- 减少线程创建和销毁的开销:线程的创建和销毁是昂贵的操作,通过复用线程可以显著减少这些开销。
- 控制并发数量:通过限制线程池中的线程数量,可以防止系统资源被过度使用,避免因过多线程导致的资源竞争和性能下降。
- 简化编程模型:线程池提供了一个简单的接口来提交任务,隐藏了线程管理的复杂性,使得编写并发程序更加容易。
以下是一个简单的线程池实现示例,使用 C++11 标准库
#include <mutex>
#include <condition_variable>
#include <queue>
#include <unistd.h>
#include <memory>
#include <functional>
#include <iostream>
#include <thread>
class ThreadPool
{
public:
//删除拷贝和复制构造函数
ThreadPool(const ThreadPool&) = delete;
ThreadPool& operator=(const ThreadPool&) = delete;
//构造函数
ThreadPool(size_t pool_size = std::thread::hardware_concurrency()):pool_size_(pool_size), stop_(false)
{
for(size_t i = 0; i < pool_size_; ++i)
{
//创建线程,并将线程函数设置为成员函数worker_thread
//这里的this指针是ThreadPool的指针
//std::bind是一个函数适配器,将成员函数转换为普通函数
//std::ref是引用包装器,将this指针包装为引用
//std::placeholders::_1是占位符,表示传入的参数
threads_.emplace_back(std::thread(&ThreadPool::worker_thread, this));
}
}
//析构函数
~ThreadPool()
{
{
std::unique_lock<std::mutex> lock(queue_mutex_);
stop_ = true;
}
condition_.notify_all();
for(auto& thread: threads_)
{
thread.join();
}
}
//添加任务
template<class F, class... Args>
void add_task(F&& f, Args&&... args)
{
//将任务封装为一个std::function
std::function<void()> task = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
{
std::unique_lock<std::mutex> lock(queue_mutex_);
tasks_.emplace(task);
}
condition_.notify_one();
}
private:
//线程函数
void worker_thread()
{
while(true)
{
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(queue_mutex_);
condition_.wait(lock, [this](){return stop_ || !tasks_.empty();});
if(stop_ && tasks_.empty())
{
return;
}
task = std::move(tasks_.front());
tasks_.pop();
}
task();
}
}
private:
//线程池的私有成员
size_t pool_size_; //线程池中线程的个数
std::vector<std::thread> threads_; //线程池中的线程
std::queue<std::function<void()>> tasks_; //任务队列
std::mutex queue_mutex_; //互斥锁
std::condition_variable condition_; //条件变量
bool stop_; //线程池是否停止的标志
};
简而言之,线程池的实现主要就是一个任务队列加一个线程数组,我们需要使用线程执行某个任务时,只需要将任务投递到任务队列中,然后线程的执行函数会自己从任务队列中取任务进行执行。