线程池
线程过多会带来调度开销,进⽽影响缓存局部性和整体性能。⽽线程池维护着多个线程,等待着监督管理者分配可并发执⾏的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利⽤,还能防⽌过分调度。可⽤线程数量应该取决于可⽤的并发处理器、处理器内核、内存、⽹络sockets等的数量。
线程池的应用场景
1.需要⼤量的线程来完成任务,且完成任务的时间⽐较短。⽐如WEB服务器完成⽹⻚请求这样的任
务,使⽤线程池技术是⾮常合适的。因为单个任务⼩,⽽任务数量巨⼤,你可以想象⼀个热⻔⽹站
的点击次数。?但对于⻓时间的任务,⽐如⼀个Telnet连接请求,线程池的优点就不明显了。因为
Telnet会话时间⽐线程的创建时间⼤多了。
2.对性能要求苛刻的应⽤,⽐如要求服务器迅速响应客⼾请求。
3.接受突发性的⼤量请求,但不⾄于使服务器因此产⽣⼤量线程的应⽤。突发性⼤量客⼾请求,在没有线程池情况下,将产⽣⼤量线程,虽然理论上⼤部分操作系统线程数⽬最⼤值不是问题,短时间内产⽣⼤量线程可能使内存到达极限,出现错误.
线程池的设计实现

上面的图就是线程池,用户往线程池中放我们的任务,由不同的线程处理函数来执行任务,这就是线程池的设计思想
cpp
#pragma once
#include <iostream>
#include <memory>
#include <vector>
#include <queue>
#include "Thread.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
using namespace ThreadMoudle;
using namespace CondModule;
using thread_t = std::shared_ptr<Thread>;
namespace ThreadPoolMoudle
{
int DefaultNum = 5; //默认线程数量
template<typename T>
class ThreadPool
{
public:
ThreadPool(int num = DefaultNum)
:_ThreadNum(num)
,_IsRuning(false)
{
for(int i = 0; i<num; i++)
{
_vecThreads.emplace_back(std::make_shared<Thread>(std::bind(&ThreadPool::HanderTask,this)));
std::cout << "线程创建完毕" << std::endl;
}
}
void Start()
{
if(_IsRuning)
{
return;
}
_IsRuning = true;
for(auto &e:_vecThreads)
{
e->Start();
}
}
void Enqueue(const T &t)
{
LockGuard lockguard(_mutex);
_qTask.push(t);
_cond.Notify();
}
void Wait()
{
for(auto &e:_vecThreads)
{
e->Join();
}
}
void Stop()
{
_IsRuning = false;
}
private:
bool IsEmpty()
{
return _qTask.empty();
}
void HanderTask()
{
while(true)
{
T t;
{
LockGuard lockguard(_mutex);
while(IsEmpty()&&_IsRuning)
{
_cond.Wait(_mutex);
}
if(IsEmpty()&&!_IsRuning)
{
//任务队列为空了但是线程还在运行直接退出
break;
}
t = _qTask.front();
_qTask.pop();
}
t();
}
}
private:
std::vector<thread_t> _vecThreads; //线程
std::queue<T> _qTask; //线程要处理的任务
int _ThreadNum; //线程数量
Mutex _mutex;
Cond _cond;
bool _IsRuning; //线程是否在运行
};
}
测试文件
cpp
#include <memory>
#include <functional>
#include "ThreadPool.hpp"
using namespace ThreadPoolMoudle;
using func_t = std::function<void()>;
Mutex mutex;
int ncnt = 1;
void push()
{
printf("ncnt: %d\n",ncnt++);
sleep(1);
}
int main()
{
std::unique_ptr<ThreadPool<func_t>> tpf = std::make_unique<ThreadPool<func_t>>();
tpf->Start();
int count = 40;
while(count--)
{
tpf->Enqueue(push);
}
tpf->Stop();
tpf->Wait();
return 0;
}
运行结果

单例模式
单例模式就是保证我们的类只能够定义出一个对象,对于线程池来说,如果创建多个线程池的话,线程数量太多了,就会造成资浪费,调度混乱,单例模式的设置需要使用static关键字,因为static修饰的变量所有类共享这个类
cpp
#pragma once
#include <iostream>
#include <memory>
#include <vector>
#include <queue>
#include "Thread.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
using namespace ThreadMoudle;
using namespace CondModule;
using namespace LockModule;
using thread_t = std::shared_ptr<Thread>;
namespace ThreadPoolMoudle
{
int DefaultNum = 5; //默认线程数量
template<typename T>
class ThreadPool
{
public:
void Enqueue(const T &t)
{
LockGuard lockguard(_mutex);
_qTask.push(t);
_cond.Notify();
}
void Start()
{
for(auto &e:_vecThreads)
{
e->Start();
}
}
void Wait()
{
for (auto &thread_ptr : _vecThreads)
{
thread_ptr->Join();
}
}
static ThreadPool<T> *GetInstance()
{
if(nullptr == Instance)
{
LockGuard lockguard(mutex);
if(nullptr == Instance)
{
Instance = new ThreadPool<T>();
Instance->Start();
}
}
return Instance;
}
ThreadPool(const ThreadPool<T> &) = delete; //禁止拷贝
ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;
private:
ThreadPool(int num = DefaultNum)
:_ThreadNum(num)
{
for(int i = 0; i<num; i++)
{
_vecThreads.emplace_back(std::make_shared<Thread>(std::bind(&ThreadPool::HanderTask,this)));
std::cout << "线程创建完毕" << std::endl;
}
}
bool IsEmpty()
{
return _qTask.empty();
}
void HanderTask()
{
while(true)
{
T t;
{
LockGuard lockguard(_mutex);
while(IsEmpty())
{
_cond.Wait(_mutex);
}
t = _qTask.front();
_qTask.pop();
}
t();
}
}
private:
std::vector<thread_t> _vecThreads; //线程
std::queue<T> _qTask; //线程要处理的任务
int _ThreadNum; //线程数量
Mutex _mutex;
Cond _cond;
static ThreadPool<T> *Instance; //单例模式
static Mutex mutex; //用来保护单例模式
};
template<typename T>
ThreadPool<T> *ThreadPool<T>::Instance = nullptr; //类中定义,类外初始化
template<typename T>
Mutex ThreadPool<T>::mutex;
}
测试文件
cpp
#include <memory>
#include <functional>
#include "ThreadPool.hpp"
using namespace ThreadPoolMoudle;
using func_t = std::function<void()>;
int ncnt = 0;
void push()
{
while(true)
{
printf("ncnt: %d\n",ncnt++);
sleep(1);
}
}
int main()
{
ThreadPool<func_t>::GetInstance()->Enqueue(push);
ThreadPool<func_t>::GetInstance()->Wait();
return 0;
}
运行结果

普通函数,需要先定义一个类的对象才能被调用,但是单例模式要求不能随便定义一个对象,而static满足了不需要定义对象就能直接调用函数的的需求