threadpool.hpp
cpp
#ifndef THREADPOOL_HPP
#define THREADPOOL_HPP
#include <iostream>
#include <thread>
#include <unordered_map>
#include <queue>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>
const int MAX_TASK_COUNT =100; //默认最大任务数量
const int IDLE_THREAD_MAX_TIME = 60; //最大空闲时间,单位s
//////////////////////PoolMode////////////////////////
enum class PoolMode
{
MODE_FIXED, //固定模式
MODE_DYNAMIC //动态模式
};
///////////////////////////////////////////////////////
///////////////////////Thread//////////////////////////
class Thread
{
public:
using threadFunctionType = std::function<void(int)>;
//构造函数
Thread(threadFunctionType func)
:threadId_(generateThreadId_++)
,func_(func)
{}
//析构函数
~Thread()=default;
//获得threadId_的值
int getThreadId() const
{
return threadId_;
}
//开启线程
void start()
{
std::thread t(func_,threadId_);
t.detach();
}
private:
int threadId_; //线程Id,对应在线程池容器中的Id
static int generateThreadId_; //生成线程I
threadFunctionType func_;
};
//类外初始化生成线程Id
int Thread::generateThreadId_ = 0;
///////////////////////////////////////////////////////
/////////////////////ThreadPool///////////////////////
class ThreadPool
{
public:
//构造函数
ThreadPool()
:poolMode_(PoolMode::MODE_FIXED)
,initThreadCount_(0)
//,currentThreadCount_(0)
,idleThreadCount_(0)
,taskCount_(0)
,taskCountMaxThreshold_(MAX_TASK_COUNT)
,isRunning_(false)
{}
//析构函数
~ThreadPool()
{
isRunning_ = false;
//获取任务队列锁
std::unique_lock<std::mutex> lock(taskMutex_);
//唤醒阻塞的线程
notEmpty_.notify_all();
//等待所有的线程回收
exitCond_.wait(lock,[&]()->bool{return threads_.size() == 0;});
}
//设置线程池模式,设置成功返回true
bool setMode(PoolMode poolMode)
{
if(isRunning_)
return false;
poolMode_=poolMode;
return true;
}
//添加任务
//返回值类型是future类,future封装的类型是:decltype后func()的返回值类型
template<typename Func,typename... Args>
auto addTask(Func&& func,Args&&... args) ->std::future<decltype(func(args...))>
{
using RType = decltype(func(args...));
auto taskPtr = std::make_shared<std::packaged_task<RType()>>(
std::bind(std::forward<Func>(func), std::forward<Args>(args)...));
std::future<RType> result = taskPtr->get_future();
//获取锁
std::unique_lock<std::mutex> lock(taskMutex_);
//判断任务队列是否为满
//wait_for:
//taskCount < taskCountMaxThreshold_ 为不满足条件 阻塞等待
//被唤醒后,条件满足则返回true,否则继续阻塞;
//超时且条件不满足则返回false
if( !notFull_.wait_for(lock,std::chrono::seconds(1),
[&]()->bool{return taskCount_ < taskCountMaxThreshold_;}) )
{
//超时且条件不满足
auto task = std::make_shared<std::packaged_task<RType()>> (
[]()->RType{return RType();});
//先对智能指针解引用获取packaged_task对象,再调用其operator()
(*task)();
std::cout<<"failed to add Task!"<<std::endl;
return task->get_future();
}
//加入任务队列
taskQueue_.emplace([taskPtr](){
//当执行taskQueue_中的元素:lambda表达式的时候,将执行以下语句
(*taskPtr)();
});
taskCount_++;
std::cout<<"add Task succeed!"<<std::endl;
//通知任务队列不为空
notEmpty_.notify_all();
//MODE_DYNAMIC模式,根据任务数量和空闲线程数量、当前线程数量 创建线程
if(poolMode_ == PoolMode::MODE_DYNAMIC && taskCount_ > idleThreadCount_
&& threads_.size() < taskCountMaxThreshold_)
{
auto threadFunc = std::bind(&ThreadPool::threadFunction, this,std::placeholders::_1);
auto threadPtr = std::make_unique<Thread> (threadFunc);
int threadId = threadPtr->getThreadId();
threads_.emplace(threadId,std::move(threadPtr));
threads_[threadId]->start();
//更新相关计数
idleThreadCount_++;
std::cout<<"thread start:"<<threadId<<std::endl;
}
return result;
}
//线程函数,Thread开始运行后执行的函数
void threadFunction(int threadId)
{
auto lastTime = std::chrono::high_resolution_clock().now();
for(;;)
{
Task task;
{
//获取任务队列锁
std::unique_lock<std::mutex> lock(taskMutex_);
//任务数量为0
while(taskCount_ == 0)
{
if(!isRunning_)
{
//线程池不是运行状态,回收线程资源
threads_.erase(threadId);
//更新相关计数
idleThreadCount_--;
//唤醒退出线程池
exitCond_.notify_all();
std::cout<<"task is exit"<<std::endl;
//结束函数,结束线程
return;
}
//MODE_DYNAMIC模式,当前线程数量大于initThreadCount_,删除空闲一定时间的线程
if(poolMode_ == PoolMode::MODE_DYNAMIC)
{
//每隔一秒轮询:空闲时间是否超过最大限制时间
if(std::cv_status::timeout == notEmpty_.wait_for(lock,std::chrono::seconds(1)))
{
auto now = std::chrono::high_resolution_clock().now();
auto dur = now -lastTime;
if(dur.count() > IDLE_THREAD_MAX_TIME && threads_.size() > initThreadCount_)
{
//空闲时间超过一定时间回收线程
threads_.erase(threadId);
//更新计数
idleThreadCount_--;
//结束函数,当前线程就结束了
std::cout<<"task is exit"<<std::endl;
return ;
}
}
}
//MODE_FIXED模式,任务为空阻塞线程直到被唤醒
else
{
notEmpty_.wait(lock);
}
}
//taskCount_ != 0的情况
//取出任务
task = taskQueue_.front();
taskQueue_.pop();
//更新相关计数
taskCount_--;
idleThreadCount_--;
//通知任务数量不为满
notFull_.notify_all();
//如果还有任务通知其他线程
if(taskCount_ > 0)
{
notEmpty_.notify_all();
}
}//离开作用域释放锁
//执行任务
if(task != nullptr)
{
task();
std::cout<<"finish task"<<std::endl;
//更新计数
idleThreadCount_++;
//执行完任务更新时间
lastTime = std::chrono::high_resolution_clock().now();
}
}
}
//开始线程池,初始线程数量默认为计算机核心数量
void start(int threadCount = std::thread::hardware_concurrency())
{
//更新运行状态
isRunning_ = true;
//更新相关计数
initThreadCount_ = threadCount;
//currentThreadCount_ = threadCount;
//创建线程类
for(int i = 0; i < initThreadCount_; i++)
{
//绑定线程函数
auto func = std::bind(&ThreadPool::threadFunction,this,std::placeholders::_1);
auto threadPtr = std::make_unique<Thread> (func);
int threadId = threadPtr->getThreadId();
threads_.emplace(threadId,std::move(threadPtr));
}
//启动线程
for(int i =0; i<initThreadCount_; i++)
{
threads_[i]->start();
idleThreadCount_++;
std::cout<<"thread start:"<<i<<std::endl;
}
}
//删除拷贝构造和拷贝赋值
ThreadPool (const ThreadPool& ) = delete;
ThreadPool& operator=(const ThreadPool& ) = delete;
private:
PoolMode poolMode_; //线程池模式
std::unordered_map<int, std::unique_ptr<Thread> > threads_; //线程容器
int initThreadCount_; //初始线程数量
//std::atomic_int currentThreadCount_; //当前线程数量
std::atomic_int idleThreadCount_; //空闲线程数量
using Task = std::function<void()>;
std::queue<Task> taskQueue_;
//std::queue< std::packaged_task<void()> > taskQueue_; //任务队列
std::atomic_int taskCount_; //任务数量
int taskCountMaxThreshold_; //任务数量最大阈值
std::mutex taskMutex_; //访问任务队列的锁
std::condition_variable notEmpty_; //任务为空条件变量
std::condition_variable notFull_; //任务为满条件变量
std::condition_variable exitCond_; //退出线程池条件变量
std::atomic_bool isRunning_; //线程池运行状态,true正在运行
};
#endif
testForThreadPool.cpp
cpp
#include "threadpool.hpp"
#include <iostream>
int sum1 (int num1, int num2, int num3)
{
return (num1+num2+num3);
}
int sum2 (int num1, int num2)
{
return (num1+num2);
}
int main()
{
{
ThreadPool pool;
pool.start();
auto futl1 = pool.addTask(sum1,1,2,3);
auto futl2 =pool.addTask(sum2,1,2);
std::cout<<"sum1:"<<futl1.get()<<std::endl;
std::cout<<"sum2:"<<futl2.get()<<std::endl;
}
std::cout<<"main out"<<std::endl;
return 0;
}