线程池(英语:thread pool):一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。 例如,线程数一般取cpu数量+2比较合适,线程数过多会导致额外的线程切换开销。 -----维基百科
注:如果对多线程还不够了解可以学习这篇博客,讲的非常好。https://www.cnblogs.com/haippy/p/3284540.html
线程池主要包括以下几个功能组成:
1、工作线程:一般初始化线程池中的维护的线程个数,当没有任务的时候,线程处于阻塞状态。直到添加新的任务到线程池中,则随机唤醒其中一个线程,来处理任务。当有多个任务到来时,则随机唤醒多个线程来处理任务。
2、任务接口:添加任务的接口,以供工作线程调度任务的执行。
3、任务队列:添加的任务先放到任务队列中去,当任务队列不为空时,则唤醒线程执行任务。
下面是代码实现,通过代码讲解工作池的实现详细过程:
#include <vector>
#include <queue>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>
#include <stdexcept>
#include <assert.h>
#include <iostream>
//任务,一般的任务都是函数处理,当然这里函数不一定是void()类型,可以定义任务函数类型
typedef std::function<void()> worker_task;
class ThreadPool {
public:
ThreadPool(size_t);
template<class F, class... Args> //任务函数参数可以是变长的
//->是c11新特性:尾返回类型。其中std::result_of<F(Args...)>::type其中是获取任务函数返回值类型
auto addTask(F&& f, Args&&... args)-> std::future<typename std::result_of<F(Args...)>::type>;
~ThreadPool();
protected:
// 线程池维护的线程个数
std::vector< std::thread > workers;
private:
ThreadPool(const ThreadPool&);//禁止复制拷贝.
const ThreadPool& operator=(const ThreadPool&);//禁止赋值
// 任务队列
std::queue<std::function<void()> > tasks;
// 锁和条件变量
std::mutex queue_mutex;
std::condition_variable condition;//当任务为空时,阻塞线程。当新任务到来时唤醒线程。
bool stop;
};
// 构造函数初始化线程的个数,用户自定义个数,可以根据自身电脑核的配置来设定。
inline ThreadPool::ThreadPool(size_t threads)
: stop(false)
{
for(size_t i = 0;i<threads;++i)
workers.emplace_back(
[this] //匿名函数
{
for(;;)
{
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(this->queue_mutex);
//如果任务队列为空,则线程会处于阻塞状态。
this->condition.wait(lock,
[this]{ return this->stop || !this->tasks.empty(); });
if(this->stop && this->tasks.empty())
return;
//当任务不为空时,则被唤醒,获取任务队列队首的任务
task = std::move(this->tasks.front());
this->tasks.pop();
}
task();//任务函数
}
}
);
}
// 添加新的任务到线程池中
template<class F, class... Args>
auto ThreadPool::addTask(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>
{
using return_type = typename std::result_of<F(Args...)>::type;//获取函数返回值类型
//std::packaged_task包装一个可调用的对象,并且允许异步获取该可调用对象产生的结果。
//具体可以参考上面给的链接
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)(); });//将任务放入任务队列
}
condition.notify_one();//唤醒阻塞的线程(随机唤醒的线程)
return res;
}
// 析构函数
inline ThreadPool::~ThreadPool()
{
{
std::unique_lock<std::mutex> lock(queue_mutex);
stop = true;
}
condition.notify_all();
for(std::thread &worker: workers)
worker.join();
}
//子类
class WorkerPool:ThreadPool{
std::vector<std::future<void>> futures;
public:
using ThreadPool::ThreadPool;
//添加任务
void launch(worker_task&);
void wait_all(void);
};
void WorkerPool::launch(worker_task &task) {
for(int i=0;i<workers.size();i++)
{
futures.push_back(addTask(task));
}
}
void WorkerPool::wait_all() {
for(auto& future:futures){
future.wait();
}
futures.clear();
}
//测试
std::atomic<int>a(0);
void helper()
{
for(int i=0;i<1000;i++)
a++;
}
int main(){
WorkerPool p(2);//构造线程池,并给线程池初始化为2个线程
std::function<void()>task1(helper);
std::function<void()>task2(helper);
p.launch(task1);
p.launch(task2);
std::cout<<a<<endl;
}