线程的反复开辟和销毁都是一个十分消耗资源和时间的事,
线程池可以提前开辟好线程保存在线程池当中,当有任务的时候,从线程池中取线程,执行完成任务后然会把他放回线程池,等待下次使用
生产者消费者模型
代码实现
#include"iostream"
#include"mutex"
#include"thread"
#include"string"
#include"condition_variable"
#include"queue"
#include"functional"
#include"vector"
class TreadPool;
class ThreadPool {
public:
ThreadPool(int numThreads): stop(false)
{
for (int i = 0; i < numThreads; i++)
{ //加线程,判断队列里面是否有任务,有就去完成
threads.emplace_back([this]() {//empalce_back函数,线程直接构造,避免复制和移动,节省资源
while (1)
{
std::unique_lock<std::mutex> lock(mtx);//1加锁
//2等待
condition.wait(lock, [this]() {
return ! tasks.empty() || stop;
});
//主线程结束,直接终止
if (stop&&tasks.empty())
{
return;
}
//3取任务
std::function<void()>task(std::move(tasks.front()));
tasks.pop();
lock.unlock();
task();
}
});
}
}
~ThreadPool() {
{
std::unique_lock<std::mutex>lock(mtx);//stop也是多线程去访问的一个变量,我们要加锁
stop = true;//
}
condition.notify_all();//为true的时候要通知把线程把所有任务完成
for (auto&t:threads)
{
t.join();
}
}
template<class F,class... Args> //F为函数 ,args 为要传入的参数
void enqueue(F&& f,Args&&...args) {//函数模板里的右值引用是万能引用,如果是右值引用就取右,左就取左
std::function<void()>task =
std::bind(std::forward<F>(f),std::forward<Args>(args)...);//用bind进行函数和参数绑定//forward进行完美转发 左值引用传左引,右引传右引
{
std::unique_lock<std::mutex>lock(mtx); //对于共享变量一定要,一点要加锁
tasks.emplace(std::move(task));//如果是左值,把左值转换成右值再加进去 emplace可以传右值,直接占用右值资源不必拷贝
}//加作用域,只有失去作用域才会调用析构函数,然后解锁
condition.notify_one();//加了任务一定要通知线程来完成
}
private:
std::vector<std::thread>threads;//线程池
std::queue<std::function<void()>>tasks;//任务队列
std::mutex mtx;
std::condition_variable condition;//条件变量
bool stop;
};
void main()
{
ThreadPool pool(4);
for (int i = 0; i <10;i++)
{
pool.enqueue([i] {
std::cout << "task:" << i << "is Running" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "task:" << i << "is Down" << std::endl;
});
}
}
: