支持Fixed和Cached模式的线程池(C++)
支持Fixed和Cached模式的线程池
简述
任务提交和返回值获取通过std::future
和std::packaged_task
完成异步获取返回值功能。
线程执行任务的思路是:
-
任务队列空
-
线程池正在运行,阻塞线程
- Cached模式视情况释放线程
-
线程池未在运行,销毁线程
-
-
任务队列不为空
-
无论线程池是否在运行,执行任务
- Cached模式视情况增加线程
-
代码
threadpool.h
#ifndef __THREADPOOL_H_ #define __THREADPOOL_H_ include<vector> include<queue> include<memory> include<atomic> include<mutex> include<condition_variable> include<functional> include<iostream> include<unordered_map> include<future> include<thread> // 线程池支持的模式 enum class PoolMode { MODE_FIXED, MODE_CACHED }; // 线程类 class Thread { public: using ThreadFunc = std::function<void(int)>; Thread(ThreadFunc func); ~Thread(); void start(); int getId() const; private: ThreadFunc func_; static int generateId_; int threadId_; }; // 线程池类 class ThreadPool { public: ThreadPool(); ~ThreadPool(); void setMode(PoolMode mode); void setInitThreadSize(size_t size); void setTaskQueMaxThreshHold(int threshhold); void setThreadSizeThreshold(int threshold); // 提交任务 template<typename F, typename... Args> auto submitTask(F&& callable, Args&&... args) -> std::future<decltype(callable(args...))> { using Return_type = decltype(callable(args...)); auto task = std::make_shared<std::packaged_task<Return_type()>>( std::bind(std::forward<F>(callable), std::forward<Args>(args)...) ); std::future<Return_type> res = task->get_future(); { std::unique_lock<std::mutex> lock(taskQueMtx_); if (!notFull_.wait_for(lock, std::chrono::seconds(1), [this]()->bool {return taskQue_.size() < taskQueMaxThreshold_; })) { std::cout << "task submit fail!" << std::endl; auto task = std::packaged_task<Return_type()>( []() {return Return_type(); } ); auto res = task.get_future(); task(); return res; } taskQue_.emplace([task]() { (*task)(); }); } return res; } void start(int initThreadSize = std::thread::hardware_concurrency()); ThreadPool(const ThreadPool&) = delete; ThreadPool& operator=(const ThreadPool&) = delete; private: void threadFunc(int threadid); // 检查pool的运行状态 bool checkRunningState() const; private: std::unordered_map<int, std::unique_ptr<Thread>> threads_; int initThreadSize_; std::atomic_int curThreadSize_; int threadSizeThreshold_; std::atomic_int idleThreadSize_; std::queue<std::function<void()>> taskQue_; int taskQueMaxThreshold_; std::mutex taskQueMtx_; std::condition_variable notFull_; std::condition_variable notEmpty_; std::condition_variable exitCond_; PoolMode poolMode_; // 运行状态 std::atomic_bool isPoolRunning_; }; endif void setMode(PoolMode mode); void setInitThreadSize(size_t size); void setTaskQueMaxThreshHold(int threshhold); void setThreadSizeThreshold(int threshold); // 提交任务 template<typename F, typename... Args> auto submitTask(F&& callable, Args&&... args) -> std::future<decltype(callable(args...))> { using Return_type = decltype(callable(args...)); auto task = std::make_shared<std::packaged_task<Return_type()>>( std::bind(std::forward<F>(callable), std::forward<Args>(args)...) ); std::future<Return_type> res = task->get_future(); { std::unique_lock<std::mutex> lock(taskQueMtx_); if (!notFull_.wait_for(lock, std::chrono::seconds(1), [this]()->bool {return taskQue_.size() < taskQueMaxThreshold_; })) { std::cout << "task submit fail!" << std::endl; auto task = std::packaged_task<Return_type()>( []() {return Return_type(); } ); auto res = task.get_future(); task(); return res; } taskQue_.emplace([task]() { (*task)(); }); } return res; } void start(int initThreadSize = std::thread::hardware_concurrency()); ThreadPool(const ThreadPool&) = delete; ThreadPool& operator=(const ThreadPool&) = delete; std::queue<std::function<void()>> taskQue_; int taskQueMaxThreshold_; std::mutex taskQueMtx_; std::condition_variable notFull_; std::condition_variable notEmpty_; std::condition_variable exitCond_; PoolMode poolMode_; // 运行状态 std::atomic_bool isPoolRunning_;
threadpool.cpp
#include "threadpool.h" #include<thread> #include<memory> const int TASK_MAX_THRESHOLD = 4; const int THREAD_MAX_THRESHOLD = 12; const int THREAD_MAX_IDLE_TIME = 10; // 单位:秒 ThreadPool::ThreadPool() :initThreadSize_(0), idleThreadSize_(0), curThreadSize_(0), taskQueMaxThreshold_(TASK_MAX_THRESHOLD), threadSizeThreshold_(THREAD_MAX_THRESHOLD), poolMode_(PoolMode::MODE_FIXED), isPoolRunning_(false) {} ThreadPool::~ThreadPool() { isPoolRunning_ = false; std::unique_lock<std::mutex> lock(taskQueMtx_); notEmpty_.notify_all(); exitCond_.wait(lock, &->bool {return threads_.size() == 0; }); } void ThreadPool::setMode(PoolMode mode) { if (checkRunningState()) return; poolMode_ = mode; } void ThreadPool::setInitThreadSize(size_t size) { initThreadSize_ = size; } void ThreadPool::setTaskQueMaxThreshHold(int threshhold) { if (checkRunningState()) return; taskQueMaxThreshold_ = threshhold; } void ThreadPool::setThreadSizeThreshold(int threshold) { if (checkRunningState()) return; if (poolMode_ == PoolMode::MODE_CACHED) { threadSizeThreshold_ = threshold; } } void ThreadPool::start(int initThreadSize) { isPoolRunning_ = true; // 设置线程池状态 initThreadSize_ = initThreadSize; curThreadSize_ = initThreadSize; // 创建Thread对象 for (int i = 0; i < initThreadSize_; ++i) { auto ptr = std::make_unique<Thread>(std::bind(&ThreadPool::threadFunc, this, std::placeholders::_1)); int threadId = ptr->getId(); threads_.emplace(threadId, std::move(ptr)); } for (int i = 0; i < initThreadSize_; ++i) { threads_[i]->start(); idleThreadSize_++; } } void ThreadPool::threadFunc(int threadid) { auto lastTime = std::chrono::high_resolution_clock().now(); while (1) { std::function<void()> task; { std::unique_lock<std::mutex> lock(taskQueMtx_); std::cout << "id" << std::this_thread::get_id() << " 尝试获取任务..." << std::endl; // 无任务时:线程池运行,阻塞线程,线程池终止,回收线程 while (taskQue_.size() == 0) { if (!isPoolRunning_) // 线程池终止,无任务,回收线程 { // 回收线程 threads_.erase(threadid); curThreadSize_--; std::cout << "threadid: " << std::this_thread::get_id() << " exit!" << std::endl; exitCond_.notify_all(); return; } // cached模式,任务队列为空:超时回收线程,未超时阻塞线程 if (poolMode_ == PoolMode::MODE_CACHED) { // 判断是否是超时唤醒 if (std::cv_status::timeout == notEmpty_.wait_for(lock, std::chrono::seconds(1))) { auto now = std::chrono::high_resolution_clock().now(); auto dur = std::chrono::duration_cast<std::chrono::seconds>(now - lastTime); if (dur.count() >= THREAD_MAX_IDLE_TIME && curThreadSize_ > initThreadSize_) { // 回收线程: threads_.erase(threadid); curThreadSize_--; idleThreadSize_--; std::cout << "threadid: " << std::this_thread::get_id() << " exit!" << std::endl; return; } } } else // fixed模式,任务队列为空:阻塞线程 { notEmpty_.wait(lock); } } // 从任务队列中取任务 task = taskQue_.front(); taskQue_.pop(); idleThreadSize_--; std::cout << "id" << std::this_thread::get_id() << " 获取任务成功!" << std::endl; if (taskQue_.size() > 0) { notEmpty_.notify_all(); } // 增加线程 if (poolMode_ == PoolMode::MODE_CACHED && taskQue_.size() > idleThreadSize_ && curThreadSize_ < threadSizeThreshold_) { std::cout << "add new thread!" << std::endl; auto ptr = std::make_unique<Thread>(std::bind(&ThreadPool::threadFunc, this, std::placeholders::_1)); int threadId = ptr->getId(); threads_.emplace(threadId, std::move(ptr)); threads_[threadId]->start(); curThreadSize_++; idleThreadSize_++; } notFull_.notify_all(); } if (task != nullptr) { task(); } idleThreadSize_++; lastTime = std::chrono::high_resolution_clock().now(); // 更新lastTime } } bool ThreadPool::checkRunningState() const { return isPoolRunning_; } // Thread int Thread::generateId_ = 0; // 通过generateId_++ 来生成threadId_ Thread::Thread(ThreadFunc func) :func_(func) ,threadId_(generateId_++) {} Thread::~Thread() { } void Thread::start() { std::thread t(func_, threadId_); t.detach(); // 设置分离线程 } int Thread::getId() const { return threadId_; } isPoolRunning_ = true; // 设置线程池状态 initThreadSize_ = initThreadSize; curThreadSize_ = initThreadSize; // 创建Thread对象 for (int i = 0; i < initThreadSize_; ++i) { auto ptr = std::make_unique<Thread>(std::bind(&ThreadPool::threadFunc, this, std::placeholders::_1)); int threadId = ptr->getId(); threads_.emplace(threadId, std::move(ptr)); } for (int i = 0; i < initThreadSize_; ++i) { threads_[i]->start(); idleThreadSize_++; } std::cout << "id" << std::this_thread::get_id() << " 尝试获取任务..." << std::endl; // 无任务时:线程池运行,阻塞线程,线程池终止,回收线程 while (taskQue_.size() == 0) { if (!isPoolRunning_) // 线程池终止,无任务,回收线程 { // 回收线程 threads_.erase(threadid); curThreadSize_--; std::cout << "threadid: " << std::this_thread::get_id() << " exit!" << std::endl; exitCond_.notify_all(); return; } // cached模式,任务队列为空:超时回收线程,未超时阻塞线程 if (poolMode_ == PoolMode::MODE_CACHED) { // 判断是否是超时唤醒 if (std::cv_status::timeout == notEmpty_.wait_for(lock, std::chrono::seconds(1))) { auto now = std::chrono::high_resolution_clock().now(); auto dur = std::chrono::duration_cast<std::chrono::seconds>(now - lastTime); if (dur.count() >= THREAD_MAX_IDLE_TIME && curThreadSize_ > initThreadSize_) { // 回收线程: threads_.erase(threadid); curThreadSize_--; idleThreadSize_--; std::cout << "threadid: " << std::this_thread::get_id() << " exit!" << std::endl; return; } } } else // fixed模式,任务队列为空:阻塞线程 { notEmpty_.wait(lock); } } // 从任务队列中取任务 task = taskQue_.front(); taskQue_.pop(); idleThreadSize_--; std::cout << "id" << std::this_thread::get_id() << " 获取任务成功!" << std::endl; if (taskQue_.size() > 0) { notEmpty_.notify_all(); } // 增加线程 if (poolMode_ == PoolMode::MODE_CACHED && taskQue_.size() > idleThreadSize_ && curThreadSize_ < threadSizeThreshold_) { std::cout << "add new thread!" << std::endl; auto ptr = std::make_unique<Thread>(std::bind(&ThreadPool::threadFunc, this, std::placeholders::_1)); int threadId = ptr->getId(); threads_.emplace(threadId, std::move(ptr)); threads_[threadId]->start(); curThreadSize_++; idleThreadSize_++; } notFull_.notify_all(); } if (task != nullptr) { task(); } idleThreadSize_++; lastTime = std::chrono::high_resolution_clock().now(); // 更新lastTime }
test.cpp
#include"threadpool.h" #include<chrono> int main() { { ThreadPool pool; pool.setMode(PoolMode::MODE_CACHED); pool.setTaskQueMaxThreshHold(20); pool.start(2); std::future<int> res1 = pool.submitTask([](int a, int b)->int {std::this_thread::sleep_for(std::chrono::seconds(2)); return a + b; }, 1, 2); auto res2 = pool.submitTask([](int a, int b, int c)->int {std::this_thread::sleep_for(std::chrono::seconds(3)) ; return a + b + c; }, 1, 2, 3); auto res3 = pool.submitTask([](int a, int b, int c)->int {std::this_thread::sleep_for(std::chrono::seconds(3)); return a * b * c; }, 1, 2, 3); auto res4 = pool.submitTask([](int a, int b, int c)->int {std::this_thread::sleep_for(std::chrono::seconds(3)); return a * b * c; }, 1, 2, 3); auto res5 = pool.submitTask([](int a, int b, int c)->int {std::this_thread::sleep_for(std::chrono::seconds(3)); return a * b * c; }, 1, 2, 3); auto res6 = pool.submitTask([](int a, int b, int c)->int {std::this_thread::sleep_for(std::chrono::seconds(3)); return a * b * c; }, 1, 2, 3); auto res7 = pool.submitTask([](int a, int b, int c)->int {std::this_thread::sleep_for(std::chrono::seconds(3)); return a * b * c; }, 1, 2, 3); auto res8 = pool.submitTask([](int a, int b, int c)->int {std::this_thread::sleep_for(std::chrono::seconds(3)); return a * b * c; }, 1, 2, 3); std::cout << res1.get() << std::endl; std::cout << res2.get() << std::endl; std::cout << res3.get() << std::endl; std::cout << res4.get() << std::endl; std::cout << res5.get() << std::endl; std::cout << res6.get() << std::endl; std::cout << res7.get() << std::endl; std::cout << res8.get() << std::endl; } std::cout << "over!" << std::endl; getchar(); return 0; std::cout << res1.get() << std::endl; std::cout << res2.get() << std::endl; std::cout << res3.get() << std::endl; std::cout << res4.get() << std::endl; std::cout << res5.get() << std::endl; std::cout << res6.get() << std::endl; std::cout << res7.get() << std::endl; std::cout << res8.get() << std::endl; } std::cout << "over!" << std::endl; getchar(); return 0; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战