手把手教你写一个线程池(C++11)
本文章会尽可能详细的为读者介绍线程池的原理,剖析我们该如何构建一个线程池。文中示意插图均为作者手绘。本文会用到C++11提供的多线程库,参考C++网站https://cplusplus.com/reference/multithreading/
线程池简介
线程池(thread pool):一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。
关于线程池的好处在此处不再赘述。下面我们来思考,一个线程池由哪些部分组成呢?线程池的运行逻辑又是怎么样的呢?
线程池类基础对象
首先,让我们从线程池的功能为起点思考,线程池是啥?通俗点说,线程池是一堆已经创建好的线程,等待着任务到来而处理任务。
- 因此,线程池需要一个线程的集合(图中中部列表)。
- 其次,需要一个任务列表(图中右部列表),来存储丢入线程池中的任务。而工作的线程将持续地去获取任务列表中地任务来处理。
- 同时,考虑到由于线程的数量需要约束,需要有一个管理者线程(Manager)来管理池内工作线程的增删。如果任务太多,核心线程(蓝色圆框)数量不够,线程可以适当增加(绿色圆圈,代表外加的非核心线程);如果有大量线程处于空闲状态,那我们就要删除一些无用的线程。
- 考虑到多线程的编程访问共享内存,我们需要一把锁来约束各线程。同时,为了起到线程拿取不到任务时阻塞等待的效果,我们需要一个条件变量cond和一个对应的互斥锁mutex。而我们可以复用此互斥锁作为线程之间的锁。
- 我们还需要一个原子变量atomic来作为我们判断线程的任务是否全部完成的标志。
- 最后,我们需要一个flag来存储线程池的状态,判断是否要退出。
综上,在class threadpool中,我们可以大致构建出我们线程池需要的对象:
//线程池状态枚举类型
typedef enum{
EXSIT = 0,
QUIT
}THREADPOOL_STATUS;
class threadpool{
/*
成员列表
*/
protected:
///@brief 任务队列相关
//队列内任务结点类型
struct TaskFunc{
TaskFunc(uint64_t extime):_extime(extime){}
int64_t _extime; //任务超时时间,
std::function<void()> _func;
};
typedef std::shared_ptr<TaskFunc> TaskFunc_ptr;
//任务队列
std::queue<TaskFunc_ptr> _Task_queue;
//任务队列上限
const size_t MAXTASKNUM = 10;
///@brief 线程相关
//线程个数
size_t _min_thread_num;
size_t _max_thread_num;
size_t _busy_thread_num = 0;
size_t _alive_thread_num = 0;
size_t _destroy_thread_num = 0;
//线程组
std::vector<std::thread*> _threads;
//管理者线程
std::thread* _manager = nullptr;
///@brief 条件变量 && 锁
//线程用 变量 && 锁
std::mutex _mutex;
std::condition_variable _cond;
//原子变量
std::atomic<int> _atomic{0};
///@brief 线程池状态变量
volatile THREADPOOL_STATUS _status;
}
下面来逐个解释具体作用:
-
任务队列相关
- TaskFunc是我们对“任务”做的第二层封装,也是最后的封装。有关Task的整体封装逻辑,详见后文的AddTask函数。
- _Task_queue是任务队列,每个结点是一个指向TaskFunc的指针。
- MAXTASKNUM是逻辑上我们设定的任务队列可以容存的最大值。一旦加入的任务数量超过了这个值,我们理应触发拒绝策略处理任务。本文为了明显的显示线程添加策略,未指定拒绝策略,并将MAXTASKNUM的值默认定为了10了。
-
线程组相关
-
_min_thread_num 线程池最小线程数
-
_max_thread_num 线程池最大线程数
-
_busy_thread_num 线程池中正在工作的线程数
-
_alive_thread_num 线程池中存活的线程数
-
_destroy_thread_num 线程池中应该销毁的线程数
-
_threads 工作线程集合
-
_manager 管理者线程
-
-
锁、条件变量、原子变量 (没啥好介绍的 略)
-
_status 代表线程池状态 枚举类型有QUIT代表要退出 EXSIT代表正常存在
线程池函数
首先来看看线程池的大致流程:
- 构造 && 析构
/*
PUBLIC API
*/
public:
/**
* @brief 构造函数 初始化状态值
* @param min max 用来初始化 _min_thread_num和_max_thread_num
*/
threadpool(size_t min,size_t max):_min_thread_num(min),_max_thread_num(max),_status(EXSIT){};
/**
* @brief 析构 stop线程池
*
*/
virtual ~threadpool(){threadpool_Stop();}
- 首先提供一系列供用户拿取线程数量的api
/**
* @brief 获取 各个种类线程个数
*
* @return size_t 线程个数
*/
size_t threadpool_GetAliveSize(){std::unique_lock<std::mutex> lck(_mutex); return this->_alive_thread_num;}
size_t threadpool_GetDestroySize(){std::unique_lock<std::mutex> lck(_mutex);return this->_destroy_thread_num;}
size_t threadpool_GetMinSize(){std::unique_lock<std::mutex> lck(_mutex);return this->_min_thread_num;}
size_t threadpool_GetMaxSize(){std::unique_lock<std::mutex> lck(_mutex);return this->_max_thread_num;}
size_t threadpool_GetBusySize(){std::unique_lock<std::mutex> lck(_mutex);return this->_busy_thread_num;}
/**
* @brief 获取线程池状态
*
* @return THREADPOOL_STATUS
*/
THREADPOOL_STATUS threadpool_GetStatus(){return this->_status;}
- 线程池运行逻辑api
/**
* @brief 初始化线程个数(用于线程池实例创建后 且 线程池start之前 以改变参数min和max大小)
*
* @param min 设置线程最小数量
* @param max 设置线程最大数量
* @return true 成功设置
* @return false
*/
bool threadpool_InitSize(size_t min,size_t max);
/**
* @brief 线程池开始运行
*
* @return int 0 --> 正常创建线程并运行 !0 --> 出错
*/
int threadpool_Start();
/**
* @brief AddTask 往线程池加入任务
*
* @tparam F 函数名
* @tparam Args 函数的可变参数列表
* @param func 函数名
* @param args 函数名的可变参数列表
* @return std::future<decltype(func(args...))> 一个future 返回值能用于异步操作
*/
template <class F,class... Args>
auto threadpool_AddTask(F&& func,Args... args) -> std::future<decltype(func(args...))>{return this->threadpool_AddTask(0,func,args...);}
template <class F,class... Args>
auto threadpool_AddTask(uint16_t extime,F&& func,Args... args) -> std::future<decltype(func(args...))>;
/**
* @brief 等待所有线程返回
*
* @param extime 等待时间(单位毫秒 ms) 超时直接返回 / 若为非正数则表永远等待
* @return true 成功返回
*/
bool threadpool_WaitEnd(int extime = 0);
/**
* @brief stop 等待所有线程返回并销毁线程池
*
*/
void threadpool_Stop();
相应实现:
bool threadpool::threadpool_InitSize(size_t min,size_t max)
{
std::unique_lock<std::mutex> lck(_mutex); //拿到锁
if(!_threads.empty()){
std::cout<<"error: 线程池已在工作!"<<std::endl;
return false;
}
_min_thread_num=min;
_max_thread_num=max;
return true;
}
int threadpool::threadpool_Start()
{
std::unique_lock<std::mutex>lck(_mutex); //拿到锁
if(!_threads.empty()){
std::cout<<"error: 线程池已在工作!"<<std::endl;
return 1;
}
//创建管理者线程
_manager=new std::thread(&threadpool::manager_callback,this);
std::cout<<"Manager thread "<<_manager->get_id()<<" is created!"<<std::endl;
//创建_min_thread_num个工作线程
for(int i=0;i<_min_thread_num;i++){
_threads.push_back(new std::thread(&threadpool::thread_callback,this));
std::cout<<"(Init)thread "<<_threads[i]->get_id()<<" is created!"<<std::endl;
_alive_thread_num++;
}
return 0;
}
bool threadpool::threadpool_WaitEnd(int extime)
{
std::unique_lock<std::mutex> lck(_mutex);
//_atomic==0代表所有任务都已经完成(见工作线程工作函数thread_callback中的操作)
//_Task_queue.empty()表示任务被取完
//如果任务都被拿完且目前被取的任务都完成了,说明线程池已经空了,所有线程都在休眠 满足要求 直接返回
if(_Task_queue.empty() && _atomic == 0)return true;
//如果不满足要求 仍有任务未完成
//则按照传入的extime超时时间,进行条件变量的等待
if(extime <= 0) _cond.wait(lck,[this]{return _Task_queue.empty() && _atomic == 0;});
else _cond.wait_for(lck,std::chrono::milliseconds(extime),[this]{return _Task_queue.empty() && _atomic == 0;});
return true;
}
void threadpool::threadpool_Stop()
{
//设置退出状态 并通知所有休眠线程
{
std::unique_lock<std::mutex> lck(_mutex);
_status = QUIT;
_cond.notify_all();
}
//此处等待所有线程返回 必须释放锁
if(_manager->joinable())_manager->join();
delete _manager;
_manager=nullptr;
for(int i=0;i<_threads.size();i++){
if(_threads[i]->joinable())_threads[i]->join();
delete _threads[i];
_threads[i]=nullptr;
}
std::unique_lock<std::mutex> lck(_mutex);
_threads.clear();
}
//这里语法有点晦涩难懂 请跟随注释逐步分析
//由于我们根据传入的func和args来确定返回值,因此我们无法像一般函数一样直接确定返回值。
//auto fun(args..) -> A 代表我们声明一个返回类型为A的函数fun
//这里 我们的返回值是一个future类,并且类模板为func(args...)的返回值。decltype()用来获取一个函数的返回值
template <class F, class... Args>
auto threadpool::threadpool_AddTask(uint16_t extime, F &&func, Args... args) -> std::future<decltype(func(args...))>
{
int64_t expireTime = (extime == 0 ? 0 : TNOWMS + extime); // 获取现在时间
//开始封装任务
using RetType = decltype(func(args...)); //获取func的返回值
//将函数func和可变参数列表args...首先通过bind()绑定为一个函数F(bind返回的是一个函数),这个函数F的类型为decltype(func(args...))(),即RetType();
//然后将这个封装了一次的函数F,再封装成一个packaged_task,这样我们就可以避免arg...不定参数集的不确定性
//最后 我们返回一个指向该packaged_task的指针packaged_tk指针
//封装示意:func(args...) == packaged_task() == (*packaged_tk)()
auto packaged_tk=std::make_shared<std::packaged_task<RetType()>>(std::bind(std::forward<F>(func),std::forward<Args>(args)...));
//最后的封装,将func(arg...)封装成一个void()类型函数。并设定超时时间
TaskFunc_ptr tsk =std::make_shared<TaskFunc>(expireTime);
tsk->_func=[packaged_tk]{
(*packaged_tk)();
};
//拿锁,访问任务队列,加入任务。并通知线程该醒了
std::unique_lock<std::mutex> lck(_mutex);
_Task_queue.push(tsk);
_cond.notify_all();
//返回一个future类型 方便异步获取
return packaged_tk->get_future();
}
- 两个线程工作函数
protected:
/**
* @brief 从任务列表试图抓取一个任务
*
* @param task 返回抓取的任务
* @return true 抓取成功
* @return false 抓取失败! 线程池退出
*/
bool gettask(TaskFunc_ptr &task);
/**
* @brief 线程工作函数
*
*/
void thread_callback();
/**
* @brief 管理者工作函数
*
*/
void manager_callback();
实现:
bool threadpool::gettask(TaskFunc_ptr &task)
{
std::unique_lock<std::mutex> lck(_mutex);
//如果任务队列为空 则线程阻塞等待
if(_Task_queue.empty()){
_cond.wait(lck,[this]{
return this->_status == QUIT || !this->_Task_queue.empty() || this->_destroy_thread_num != 0;
});
}
//如果管理者判断要销毁线程
if(_destroy_thread_num !=0){
_destroy_thread_num -- ;
_alive_thread_num -- ;
return false;
}
//如果要退出了 就不允许继续拿取任务 返回false
if(this->_status == QUIT)return false;
//否则 一切正常 拿取任务
if(!_Task_queue.empty()){
task=std::move(_Task_queue.front()); //避免拷贝
_Task_queue.pop();
return true;
}
return true;
}
void threadpool::thread_callback()
{
//只要线程池不退出 线程就一直循环工作
while(this->_status == EXSIT){
TaskFunc_ptr task;
int ret=gettask(task); //尝试拿取任务
if(ret){
//如果正常抓取到了任务
std::unique_lock<std::mutex> lck(_mutex);
_busy_thread_num++; //线程入busy状态
lck.unlock();
++_atomic; //_atomic表示一个任务被取出且被开始执行
try
{
if(task->_extime > 0 && task->_extime < TNOWMS){
//任务超时
}
else {
task->_func();
}
}
catch(...)
{
std::cout<<"任务执行出错!"<<std::endl;
}
--_atomic; //--_atomic 表示一个被取出的任务被完成了
lck.lock();
_busy_thread_num--;
lck.unlock();
lck.lock();
//线程取出任务后,需要完成任务。有可能完成任务很费时间。
//因此 只有所有任务全部被取出(任务队列为空) 且所有被取出的任务都被完成(_atomic == 0) 才能说明所有线程完成任务
if(_atomic == 0 && _Task_queue.empty()){
//如果任务队列为空 且 所有任务都执行完成 则给wait函数广播发送信号
_cond.notify_all();
}
} else {
std::unique_lock<std::mutex> lck(_mutex);
std::cout<<"Thread "<<std::this_thread::get_id()<<" is Killed!"<<std::endl;
return;
}
}
std::cout<<"Thread "<<std::this_thread::get_id()<<" is Exited!"<<std::endl;
return ;
}
void threadpool::manager_callback()
{
//每隔2秒检测一次
while(this->_status != QUIT){
std::this_thread::sleep_for(std::chrono::seconds(2));
std::unique_lock<std::mutex> lck(_mutex);
//增加线程策略 如果任务列表超了并且线程数量未达上限
if(_Task_queue.size() >= MAXTASKNUM && _alive_thread_num<_max_thread_num){
for(int i=0;i<=0 && _alive_thread_num < _max_thread_num;i++){
_threads.push_back(new std::thread(thread_callback,this));
_alive_thread_num++;
std::cout<<"thread "<<_threads[_alive_thread_num-1]->get_id()<<"is created!"<<std::endl;
}
}
//删除线程策略
if(_alive_thread_num > _min_thread_num && 2*_busy_thread_num <_alive_thread_num){
_destroy_thread_num ++;
_cond.notify_all();
}
}
}
总代码 && 测试
threadpool.h
#ifndef THREADPOOL_CPP
#define THREADPOOL_CPP
#include <iostream>
#include <functional>
#include <future>
#include <thread>
#include <mutex>
#include <queue>
#include <memory>
#include <vector>
#include <Windows.h>
#define TNOW getNow()
#define TNOWMS getNowMs()
/**
* @brief 用来获取当前时间
*
* @param tv
*/
void getNow(timeval *tv);
int64_t getNowMs();
int gettimeofday(struct timeval &tv);
typedef enum{
EXSIT = 0,
QUIT
}THREADPOOL_STATUS;
class threadpool{
/*
成员列表
*/
protected:
///@brief 任务队列相关
//队列内任务结点类型
struct TaskFunc{
TaskFunc(uint64_t extime):_extime(extime){}
int64_t _extime; //任务超时时间,
std::function<void()> _func;
};
typedef std::shared_ptr<TaskFunc> TaskFunc_ptr;
//任务队列
std::queue<TaskFunc_ptr> _Task_queue;
//任务队列上限
const size_t MAXTASKNUM = 10;
///@brief 线程相关
//线程个数
size_t _min_thread_num;
size_t _max_thread_num;
size_t _busy_thread_num = 0;
size_t _alive_thread_num = 0;
size_t _destroy_thread_num = 0;
//线程组
std::vector<std::thread*> _threads;
//管理者线程
std::thread* _manager = nullptr;
///@brief 条件变量 && 锁
//线程用 变量 && 锁
std::mutex _mutex;
std::condition_variable _cond;
//原子变量
std::atomic<int> _atomic{0};
///@brief 线程池状态变量
volatile THREADPOOL_STATUS _status;
/*
PUBLIC API
*/
public:
/**
* @brief 构造函数 初始化状态值
*
*/
threadpool(size_t min,size_t max):_min_thread_num(min),_max_thread_num(max),_status(EXSIT){};
/**
* @brief 析构 stop线程池
*
*/
virtual ~threadpool(){threadpool_Stop();}
/**
* @brief 获取 各个种类线程个数
*
* @return size_t 线程个数
*/
size_t threadpool_GetAliveSize(){std::unique_lock<std::mutex> lck(_mutex); return this->_alive_thread_num;}
size_t threadpool_GetDestroySize(){std::unique_lock<std::mutex> lck(_mutex);return this->_destroy_thread_num;}
size_t threadpool_GetMinSize(){std::unique_lock<std::mutex> lck(_mutex);return this->_min_thread_num;}
size_t threadpool_GetMaxSize(){std::unique_lock<std::mutex> lck(_mutex);return this->_max_thread_num;}
size_t threadpool_GetBusySize(){std::unique_lock<std::mutex> lck(_mutex);return this->_busy_thread_num;}
/**
* @brief 获取线程池状态
*
* @return THREADPOOL_STATUS
*/
THREADPOOL_STATUS threadpool_GetStatus(){return this->_status;}
/**
* @brief 初始化线程个数
*
* @param min 设置线程最小数量
* @param max 设置线程最大数量
* @return true 成功设置
* @return false
*/
bool threadpool_InitSize(size_t min,size_t max);
/**
* @brief 线程池开始运行
*
* @return int 0 --> 正常创建线程并运行 !0 --> 出错
*/
int threadpool_Start();
/**
* @brief AddTask 往线程池加入任务
*
* @tparam F 函数名
* @tparam Args 函数的可变参数列表
* @param func 函数名
* @param args 函数名的可变参数列表
* @return std::future<decltype(func(args...))> 一个future 返回值能用于异步操作
*/
template <class F,class... Args>
auto threadpool_AddTask(F&& func,Args... args) -> std::future<decltype(func(args...))>{return this->threadpool_AddTask(0,func,args...);}
template <class F,class... Args>
auto threadpool_AddTask(uint16_t extime,F&& func,Args... args) -> std::future<decltype(func(args...))>;
/**
* @brief 等待所有线程返回
*
* @param extime 等待时间(单位毫秒 ms) 超时直接返回 / 若为非正数则表永远等待
* @return true 成功返回
*/
bool threadpool_WaitEnd(int extime = 0);
/**
* @brief stop 等待所有线程返回并销毁线程池
*
*/
void threadpool_Stop();
protected:
/**
* @brief 从任务列表试图抓取一个任务
*
* @param task 返回抓取的任务
* @return true 抓取成功
* @return false 抓取失败! 线程池退出
*/
bool gettask(TaskFunc_ptr &task);
/**
* @brief 线程工作函数
*
*/
void thread_callback();
/**
* @brief 管理者工作函数
*
*/
void manager_callback();
};
template <class F, class... Args>
auto threadpool::threadpool_AddTask(uint16_t extime, F &&func, Args... args) -> std::future<decltype(func(args...))>
{
int64_t expireTime = (extime == 0 ? 0 : TNOWMS + extime); // 获取现在时间
using RetType = decltype(func(args...));
auto packaged_tk=std::make_shared<std::packaged_task<RetType()>>(std::bind(std::forward<F>(func),std::forward<Args>(args)...));
TaskFunc_ptr tsk =std::make_shared<TaskFunc>(expireTime);
tsk->_func=[packaged_tk]{
(*packaged_tk)();
};
std::unique_lock<std::mutex> lck(_mutex);
_Task_queue.push(tsk);
_cond.notify_all();
return packaged_tk->get_future();
}
#endif
threadpool.cpp
#include "threadpool.h"
using namespace std;
bool threadpool::threadpool_InitSize(size_t min,size_t max)
{
std::unique_lock<std::mutex> lck(_mutex); //拿到锁
if(!_threads.empty()){
std::cout<<"error: 线程池已在工作!"<<std::endl;
return false;
}
_min_thread_num=min;
_max_thread_num=max;
return true;
}
int threadpool::threadpool_Start()
{
std::unique_lock<std::mutex>lck(_mutex);
if(!_threads.empty()){
std::cout<<"error: 线程池已在工作!"<<std::endl;
return 1;
}
_manager=new std::thread(&threadpool::manager_callback,this);
std::cout<<"Manager thread "<<_manager->get_id()<<" is created!"<<std::endl;
for(int i=0;i<_min_thread_num;i++){
_threads.push_back(new std::thread(&threadpool::thread_callback,this));
std::cout<<"(Init)thread "<<_threads[i]->get_id()<<" is created!"<<std::endl;
_alive_thread_num++;
}
return 0;
}
bool threadpool::threadpool_WaitEnd(int extime)
{
std::unique_lock<std::mutex> lck(_mutex);
if(_Task_queue.empty() && _atomic == 0)return true;
if(extime <= 0) _cond.wait(lck,[this]{return _Task_queue.empty() && _atomic == 0;});
else _cond.wait_for(lck,std::chrono::milliseconds(extime),[this]{return _Task_queue.empty() && _atomic == 0;});
return true;
}
void threadpool::threadpool_Stop()
{
{
std::unique_lock<std::mutex> lck(_mutex);
_status = QUIT;
_cond.notify_all();
}
//此处等待所有线程返回 必须释放锁
if(_manager->joinable())_manager->join();
delete _manager;
_manager=nullptr;
for(int i=0;i<_threads.size();i++){
if(_threads[i]->joinable())_threads[i]->join();
delete _threads[i];
_threads[i]=nullptr;
}
std::unique_lock<std::mutex> lck(_mutex);
_threads.clear();
}
bool threadpool::gettask(TaskFunc_ptr &task)
{
std::unique_lock<std::mutex> lck(_mutex);
//如果任务队列为空 则线程阻塞等待
if(_Task_queue.empty()){
_cond.wait(lck,[this]{
return this->_status == QUIT || !this->_Task_queue.empty() || this->_destroy_thread_num != 0;
});
}
//如果管理者判断要销毁线程
if(_destroy_thread_num !=0){
_destroy_thread_num -- ;
_alive_thread_num -- ;
return false;
}
//如果要退出了 就不允许继续拿取任务 返回false
if(this->_status == QUIT)return false;
//否则 一切正常 拿取任务
if(!_Task_queue.empty()){
task=std::move(_Task_queue.front()); //避免拷贝
_Task_queue.pop();
return true;
}
return true;
}
void threadpool::thread_callback()
{
while(this->_status == EXSIT){
TaskFunc_ptr task;
int ret=gettask(task);
if(ret){
//如果正常抓取到了任务
std::unique_lock<std::mutex> lck(_mutex);
_busy_thread_num++;
lck.unlock();
++_atomic;
try
{
if(task->_extime > 0 && task->_extime < TNOWMS){
//任务超时
}
else {
task->_func();
}
}
catch(...)
{
std::cout<<"任务执行出错!"<<std::endl;
}
--_atomic;
lck.lock();
_busy_thread_num--;
lck.unlock();
lck.lock();
if(_atomic == 0 && _Task_queue.empty()){
//如果任务队列为空 且 所有任务都执行完成 则给wait函数广播发送信号
_cond.notify_all();
}
} else {
std::unique_lock<std::mutex> lck(_mutex);
std::cout<<"Thread "<<std::this_thread::get_id()<<" is Killed!"<<std::endl;
return;
}
}
std::cout<<"Thread "<<std::this_thread::get_id()<<" is Exited!"<<std::endl;
return ;
}
void threadpool::manager_callback()
{
//每隔2秒检测一次
while(this->_status != QUIT){
std::this_thread::sleep_for(std::chrono::seconds(2));
std::unique_lock<std::mutex> lck(_mutex);
//增加线程策略
if(_Task_queue.size() >= MAXTASKNUM && _alive_thread_num<_max_thread_num){
for(int i=0;i<=0 && _alive_thread_num < _max_thread_num;i++){
_threads.push_back(new std::thread(thread_callback,this));
_alive_thread_num++;
std::cout<<"thread "<<_threads[_alive_thread_num-1]->get_id()<<"is created!"<<std::endl;
}
}
//删除线程策略
if(_alive_thread_num > _min_thread_num && 2*_busy_thread_num <_alive_thread_num){
_destroy_thread_num ++;
_cond.notify_all();
}
}
}
int gettimeofday(struct timeval &tv)
{
#if WIN32
time_t clock;
struct tm tm;
SYSTEMTIME wtm;
GetLocalTime(&wtm);
tm.tm_year = wtm.wYear - 1900;
tm.tm_mon = wtm.wMonth - 1;
tm.tm_mday = wtm.wDay;
tm.tm_hour = wtm.wHour;
tm.tm_min = wtm.wMinute;
tm.tm_sec = wtm.wSecond;
tm. tm_isdst = -1;
clock = mktime(&tm);
tv.tv_sec = clock;
tv.tv_usec = wtm.wMilliseconds * 1000;
return 0;
#else
return ::gettimeofday(&tv, 0);
#endif
}
void getNow(timeval *tv)
{
#if TARGET_PLATFORM_IOS || TARGET_PLATFORM_LINUX
int idx = _buf_idx;
*tv = _t[idx];
if(fabs(_cpu_cycle - 0) < 0.0001 && _use_tsc)
{
addTimeOffset(*tv, idx);
}
else
{
TC_Common::gettimeofday(*tv);
}
#else
gettimeofday(*tv);
#endif
}
int64_t getNowMs()
{
struct timeval tv;
getNow(&tv);
return tv.tv_sec * (int64_t)1000 + tv.tv_usec / 1000;
}
测试代码:
test.cpp
#include <iostream>
#include "threadpool.h"
#include <memory>
using namespace std;
int count=0;
mutex mut;
void task(){
for(int i=1;i<=10;i++){
this_thread::sleep_for(chrono::milliseconds(1000));
unique_lock<mutex> lck(mut);
count++;
cout<<" count = "<<count<<endl;
}
}
void do_other_things(){
this_thread::sleep_for(chrono::seconds(10));
cout<<"do other things!"<<endl;
}
int main(){
threadpool mypool(8,100);
cout<<mypool.threadpool_GetAliveSize()<<endl;
mypool.threadpool_Start();
cout<<mypool.threadpool_GetAliveSize()<<endl;
for(int i=0;i<20;i++)
mypool.threadpool_AddTask(&task);
mypool.threadpool_WaitEnd(-1);
cout<<"here"<<endl;
mypool.threadpool_AddTask(&do_other_things);
mypool.threadpool_WaitEnd(-1);
mypool.threadpool_Stop();
return 0;
}
测试结果:
0
Manager thread 2 is created!
(Init)thread 3 is created!
(Init)thread 4 is created!
(Init)thread 5 is created!
(Init)thread 6 is created!
(Init)thread 7 is created!
(Init)thread 8 is created!
(Init)thread 9 is created!
(Init)thread 10 is created!
8
count = 1
count = 2
count = 3
count = 4
count = 5
count = 6
count = 7
count = 8
count = 9
thread 11is created!
count = 10
count = 11
count = 12
count = 13
count = 14
count = 15
count = 16
count = 17
count = 18
count = 19
count = 20
count = 21
count = 22
count = 23
count = 24
count = 25
count = 26
count = 27
thread 12is created!
count = 28
count = 29
count = 30
count = 31
count = 32
count = 33
count = 34
count = 35
count = 36
count = 37
count = 38
count = 39
count = 40
count = 41
count = 42
count = 43
count = 44
count = 45
thread 13is created!
count = 46
count = 47
count = 48
count = 49
count = 50
count = 51
count = 52
count = 53
count = 54
count = 55
count = 56
count = 57
count = 58
count = 59
count = 60
count = 61
count = 62
count = 63
count = 64
count = 65
count = 66
count = 67
count = 68
count = 69
count = 70
count = 71
count = 72
count = 73
count = 74
count = 75
count = 76
count = 77
count = 78
count = 79
count = 80
count = 81
count = 82
count = 83
count = 84
count = 85
count = 86
count = 87
count = 88
count = 89
count = 90
count = 91
count = 92
count = 93
count = 94
count = 95
count = 96
count = 97
count = 98
count = 99
count = 100
count = 101
count = 102
count = 103
count = 104
count = 105
count = 106
count = 107
count = 108
count = 109
count = 110
count = 111
count = 112
count = 113
count = 114
count = 115
count = 116
count = 117
count = 118
count = 119
count = 120
count = 121
count = 122
count = 123
count = 124
count = 125
count = 126
count = 127
count = 128
count = 129
count = 130
count = 131
count = 132
count = 133
count = 134
count = 135
count = 136
count = 137
count = 138
count = 139
count = 140
count = 141
count = 142
count = 143
count = 144
count = 145
count = 146
count = 147
count = 148
count = 149
count = 150
count = 151
count = 152
count = 153
count = 154
count = 155
count = 156
count = 157
count = 158
count = 159
count = 160
count = 161
count = 162
count = 163
count = 164
count = 165
count = 166
count = 167
count = 168
count = 169
count = 170
count = 171
count = 172
count = 173
count = 174
count = 175
count = 176
count = 177
count = 178
count = 179
count = 180
count = 181
count = 182
count = 183
count = 184
count = 185
count = 186
count = 187
count = 188
count = 189
count = 190
count = 191
count = 192
count = 193
count = 194
count = 195
count = 196
count = 197
count = 198
count = 199
Thread 6 is Killed!
count = 200
here
Thread 4 is Killed!
Thread 3 is Killed!
do other things!
Thread 11 is Killed!
Thread 5 is Killed!
Thread 9 is Killed!
Thread 10 is Killed!
Thread 12 is Killed!
Thread 8 is Killed!
Thread 13 is Killed!
Thread 7 is Killed!
总结
线程池作为非常关键的自定义组件,理应熟练掌握。而构建一个线程池实际不难,关键就是要掌握整体逻辑。
课程学习连接:https://xxetb.xet.tech/s/4czPSo
Github链接:Github
如果对你有帮助 请点个赞赞吧喵 谢谢喵 有错误欢迎指出