C++基于新特性的优先队列异步可调度线程池

概述:

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等........

失去/C++开源类 - Gitee.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值