概述:
C++基于新特性的优先队列异步可调度线程池;
实现了模拟操作系统中的优先级任务调度,
实现了任务的优先级智能化减轻优先级,让后面一直没有执行的任务可以得到执行,
实现了异步操作,可获取返回值。
运行结果:
ThreadPool.hpp
#pragma once
#include <thread>
#include <mutex>
#include <queue>
#include <atomic>
#include <functional>
#include <condition_variable>
#include <map>
#include <vector>
#include <future>
#include <type_traits>
// 优先队列可异步线程池类,用于管理多个工作线程并执行任务
class ThreadPool {
public:
// 单例模式,推荐首先只在main中先进行指定最小线程数
static ThreadPool* getSingleThreadPool(int minThreadCount = 1, int maxThreadCount = std::thread::hardware_concurrency());
// 释放全部内存,包括new静态的
static void release();
// 等待任务全部执行完成
void waitUntilAllTasksFinished();
~ThreadPool(); // 析构函数,销毁所有线程
// -----通过SFINAE (Substitution Failure Is Not An Error) 确保仅当F返回void时使用无返回版本
// 添加无返回值的任务到任务队列,F(Args...) 的结果类型为 void 时启用
template<typename F, typename... Args, typename = std::enable_if_t<std::is_void<typename std::result_of<F(Args...)>::type>::value>>
void addTask(F&& f, Args&&... args);
// 添加带返回值的任务,返回一个future用于获取结果,不为 void 则启动
template<typename F, typename... Args, typename = std::enable_if_t<!std::is_void<typename std::result_of<F(Args...)>::type>::value>>
auto addTask(F&& f, Args&&... args)->std::future<typename std::result_of<F(Args...)>::type>;
// 带线程优先级的添加任务
template<typename F, typename... Args, typename = std::enable_if_t<std::is_void<typename std::result_of<F(Args...)>::type>::value>>
void addTask(int priority, F&& f, Args&&... args);
// 添加带返回值的任务,返回一个future用于获取结果,不为 void 则启动
template<typename F, typename... Args, typename = std::enable_if_t<!std::is_void<typename std::result_of<F(Args...)>::type>::value>>
auto addTask(int priority, F&& f, Args&&... args)->std::future<typename std::result_of<F(Args...)>::type>;
private:
struct Task {
int priority; // 任务优先级
std::function<void()> task;
Task() : task(nullptr), priority(0) { }
Task(std::function<void()>& task, int priority = 0) : task(std::move(task)), priority(priority) { }
};
// 自定义比较器(较大的值优先)
struct CompareProcess {
bool operator()(const Task& p1, const Task& p2) {
return p1.priority < p2.priority; // 大根堆
}
};
private:
// 构造函数,参数为最小和最大线程数
ThreadPool(int min, int max);
void threadPoolManager(); // 线程池管理器,用于添加或减少工作线程
void threadPoolWorker(); // 工作线程的函数,从任务队列当中获取任务并执行
private:
// 静态成员变量存储单例实例
static ThreadPool* m_threadPoolInstance;
// 确保线程安全的标志(只允许调用一次),本质是为0,1的锁
static std::mutex initInstanceFlag;
std::map<std::thread::id, std::thread> m_workerThread; // 存储工作线程
int m_minThreadCount; // 最小线程数
int m_maxThreadCount; // 最大线程数
int m_threadPriorityNum; // 当任务队列中不为空时每一个指定了优先级的任务都要减去这个数
std::atomic<bool> m_stop; // 用于停止线程池的标志
std::atomic<int> m_curThreadCount; // 当前线程数量
std::atomic<int> m_idleThreadCount; // 某个时刻空闲线程数量
std::atomic<int> m_exitThreadCount; // 允许退出的线程数量
std::priority_queue<Task, std::vector<Task>, CompareProcess> m_tasks; // 优先任务队列
std::mutex m_idsMutex; // 线程ID列表互斥锁
std::mutex m_queueMutex; // 任务队列互斥锁
std::condition_variable m_condition; // 用于唤醒工作线程的条件变量
};
// 静态成员变量类外初始化
ThreadPool* ThreadPool::m_threadPoolInstance = nullptr;
std::mutex ThreadPool::initInstanceFlag;
#include <iostream>
using namespace std;
//单例模式
ThreadPool* ThreadPool::getSingleThreadPool(int minThreadCount, int maxThreadCount)
{
// 双重检测法(方便释放内存之后再创建)
if (m_threadPoolInstance == nullptr)
{
lock_guard<mutex> lock(initInstanceFlag);
if (m_threadPoolInstance == nullptr)
m_threadPoolInstance = new ThreadPool(minThreadCount, maxThreadCount);
}
return m_threadPoolInstance;
}
void ThreadPool::release()
{
if (m_threadPoolInstance)
delete m_threadPoolInstance; // 释放内存
m_threadPoolInstance = nullptr; // 清空指针,防止悬挂指针
}
// 等待任务全部执行完成
void ThreadPool::waitUntilAllTasksFinished()
{
while (true)
{
{
unique_lock<std::mutex> lock(m_queueMutex);
if (m_tasks.empty())
{
cout << "等待结束了!!!!" << endl;
return;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
}
// 构造函数实现
ThreadPool::ThreadPool(int min, int max) : m_maxThreadCount(max),
m_minThreadCount(min), m_stop(false), m_exitThreadCount(0), m_threadPriorityNum(1)
{
// 初始化空闲和当前线程数
m_idleThreadCount = m_curThreadCount = min;
cout << "设定最小线程数量: " << m_curThreadCount << " ,最大支持线程数:" << max << endl;
thread m_manager(&ThreadPool::threadPoolManager, this); // 启动管理线程
m_workerThread.insert(make_pair(m_manager.get_id(), move(m_manager)));
// 创建初始的工作线程
for (int i = 0; i < m_curThreadCount; ++i)
{
thread t(&ThreadPool::threadPoolWorker, this);
m_workerThread.insert(make_pair(t.get_id(), move(t)));
}
}
// 析构函数实现:清理所有线程资源
ThreadPool::~ThreadPool()
{
m_stop = true; // 设置停止标志
m_condition.notify_all(); // 唤醒所有线程以进行退出
// 连接所有工作线程,确保它们退出
for (auto& it : m_workerThread)
{
thread& t = it.second;
// 检查线程是否是可连接的(没有被join 或 detach)
if (t.joinable())
{
cout << "********** 线程 " << t.get_id() << " 将要退出了..." << endl;
t.join();
}
}
}
// 添加无返回值的任务到任务队列
template<typename F, typename... Args, typename>
void ThreadPool::addTask(F&& f, Args&&... args)
{
// 使用绑定化参数的形式进行打包函数成可调用对象
function<void()> task = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
{
// 使用 std::move 移动 task 到 newTask,确保 task 的资源被移动
Task newTask(task);
std::unique_lock<std::mutex> lock(m_queueMutex);
m_tasks.emplace(move(newTask));
}
m_condition.notify_one(); // 通知一个工作线程开始执行任务
}
// 添加带返回值的任务,返回一个future用于获取结果
template<typename F, typename... Args, typename>
auto ThreadPool::addTask(F&& f, Args&&... args) -> future<typename result_of<F(Args...)>::type>
{
using returnType = typename result_of<F(Args...)>::type;
// 使用packaged_task包装任务
auto task = make_shared<packaged_task<returnType()>>(
bind(forward<F>(f), forward<Args>(args)...)
);
future<returnType> res = task->get_future(); // 获取任务的future
{
function<void()> taskFunction([task]() { (*task)(); });
Task newTask(taskFunction);
unique_lock<mutex> lock(m_queueMutex); // 锁定任务队列以进行线程安全操作
// 将task转移到lambda表达式中
m_tasks.emplace(move(newTask)); // 将任务添加至任务队列
}
m_condition.notify_one(); // 通知一个工作线程开始执行任务
return res; // 返回future对象
}
// 添加无返回值的任务到任务队列
template<typename F, typename... Args, typename>
void ThreadPool::addTask(int priority, F&& f, Args&&... args)
{
// 使用绑定化参数的形式进行打包函数成可调用对象
function<void()> task = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
{
// 使用 std::move 移动 task 到 newTask,确保 task 的资源被移动
Task newTask(task, priority);
std::unique_lock<std::mutex> lock(m_queueMutex);
if (m_threadPriorityNum > 1 && m_tasks.empty())
m_threadPriorityNum = 1; //任务队列为零时进行重置
else if (m_threadPriorityNum > 1)
{
cout << "发送优先级减少:m_threadPriorityNum:" << m_threadPriorityNum << endl;
newTask.priority -= m_threadPriorityNum;
}
//下一个任务对应减数(反过来说就是其他都加 1 )
++m_threadPriorityNum;
m_tasks.emplace(move(newTask));
}
m_condition.notify_one(); // 通知一个工作线程开始执行任务
}
// 添加带返回值的任务,返回一个future用于获取结果
template<typename F, typename... Args, typename>
auto ThreadPool::addTask(int priority, F&& f, Args&&... args) -> future<typename result_of<F(Args...)>::type>
{
using returnType = typename result_of<F(Args...)>::type;
// 使用packaged_task包装任务
auto task = make_shared<packaged_task<returnType()>>(
bind(forward<F>(f), forward<Args>(args)...)
);
future<returnType> res = task->get_future(); // 获取任务的future
{
function<void()> taskFunction([task]() { (*task)(); });
Task newTask(taskFunction, priority);
unique_lock<mutex> lock(m_queueMutex); // 锁定任务队列以进行线程安全操作
if (m_threadPriorityNum > 1 && m_tasks.empty())
m_threadPriorityNum = 1; //任务队列为零时进行重置
else if (m_threadPriorityNum > 1)
{
cout << "发送优先级减少:m_threadPriorityNum:" << m_threadPriorityNum << endl;
newTask.priority -= m_threadPriorityNum;
}
//下一个任务对应减数(反过来说就是其他都加 1 )
++m_threadPriorityNum;
// 将task转移到lambda表达式中
m_tasks.emplace(move(newTask)); // 将任务添加至任务队列
}
m_condition.notify_one(); // 通知一个工作线程开始执行任务
return res; // 返回future对象
}
// 线程管理函数,调整工作线程数量以满足任务量需求
void ThreadPool::threadPoolManager()
{
while (!m_stop.load())
{
this_thread::sleep_for(chrono::seconds(2)); // 定期检查线程状态
int idle = m_idleThreadCount.load(); // 当前空闲线程数
int current = m_curThreadCount.load(); // 当前工作线程总数
int taskCount = m_tasks.size(); // 任务队列中的任务数量
cout << "idle:" << idle << ",current:" << current << endl;
// 如果空闲线程数过多且当前线程数超过最小线程数,准备销毁多余线程
if (idle > current / 2 && current > m_minThreadCount)
{
m_exitThreadCount += 2; // 标记将要退出的线程数
cout << "放入了要销毁的线程" << endl;
m_condition.notify_all(); // 通知所有工作线程检查状态
}
// 如果任务队列中有任务但当前线程数不足,创建新线程
else if (idle == 0 && current < m_maxThreadCount)
{
int threadsToCreate = min(m_maxThreadCount - current, 2); // 每次最多创建2个线程
for (int i = 0; i < threadsToCreate; ++i)
{
thread t(&ThreadPool::threadPoolWorker, this);
{
lock_guard<mutex> locker(m_idsMutex);
m_workerThread.insert({ t.get_id(), move(t) }); // 保存新创建的线程
}
m_idleThreadCount++;
m_curThreadCount++;
}
cout << "当前任务线程总数:" << m_curThreadCount << endl;
}
}
}
// 工作线程函数,从任务队列中提取任务并执行
void ThreadPool::threadPoolWorker()
{
while (!m_stop.load()) // 只要线程池没有停止,工作线程就继续运行
{
Task task; // 初始化一个空的任务
{
unique_lock<mutex> locker(m_queueMutex); // 加锁以保护任务队列和条件变量
// 如果任务队列为空且线程池未停止,则等待新任务
while (!m_stop && m_tasks.empty())
{
m_condition.wait(locker); // 等待条件变量被唤醒
// 检查是否需要退出
if (m_exitThreadCount.load() > 0)
{
cout << "*****线程任务销毁, ID: " << this_thread::get_id() << endl;
m_exitThreadCount--; // 减少退出线程计数
m_curThreadCount--; // 减少当前线程总数
m_idleThreadCount--; // 减少空闲线程数
// 在走出锁块外部去做线程清理,避免持锁时间过长
{
unique_lock<mutex> lck(m_idsMutex); // 再次加锁以进行线程清理
auto it = m_workerThread.find(this_thread::get_id()); // 查找当前线程
if (it != m_workerThread.end())
{
it->second.detach(); // 将当前线程与管理线程分离,允许它独立运行
m_workerThread.erase(it); // 从工作线程列表中移除当前线程
//cout << this_thread::get_id() << "线程退出!" << endl;
}
}
return; // 线程退出
}
}
// 如果任务队列不为空,取出一个任务
if (!m_tasks.empty())
{
//cout << "取出一个任务..." << endl;
task = m_tasks.top(); // 移动任务到局部变量,以避免在解锁后访问已删除的任务
m_tasks.pop(); // 从任务队列中移除任务
if (m_tasks.empty())
m_condition.notify_all();
}
}
// 如果有任务,执行它
if (task.task)
{
m_idleThreadCount--; // 减少空闲线程数
task.task(); // 执行任务
m_idleThreadCount++; // 任务执行完毕后,增加空闲线程数
}
}
}
test1:
#include "ThreadPool.hpp"
#include <iostream>
using namespace std;
int calc(int x, int y)
{
this_thread::sleep_for(chrono::seconds(5));
return x * y;
}
void calc2(int x, int y)
{
this_thread::sleep_for(chrono::seconds(4));
cout << "x:" << x << ",y:" << y << endl;
return;
}
void calc3(int x, int y)
{
this_thread::sleep_for(chrono::seconds(4));
cout << "带线程优先级***," << "x:" << x << ",y:" << y << endl;
return;
}
int main() {
ThreadPool* pool = ThreadPool::getSingleThreadPool(4);
vector<future<int>> results;
for (int i = 0; i < 5; ++i) {
results.emplace_back(pool->addTask(calc, i, i * 2));
}
pool->addTask(10, calc3, 1, 1);
pool->addTask(10, calc3, 2, 2);
// 等待并打印结果
for (auto&& res : results) {
cout << "线程函数返回值: " << res.get() << endl;
}
//ThreadPool* pool2 = ThreadPool::getSingleThreadPool(4);
for (int i = 0; i < 6; ++i) {
pool->addTask(calc2, i, i * 2);
}
pool->addTask(10, calc3, 0, 0);
pool->waitUntilAllTasksFinished();
pool->release();
return 0;
}
希望可以互相讨论进步,代码获取(欢迎start,会继续更新):
需要视频讲解b站搜:C++自定义Graph有向图类,可直接嵌入使用_哔哩哔哩_bilibili等........