当前位置: 首页 > article >正文

C++线程池

使用线程情况比较频繁的地方,由于线程的创建及销毁都会产生对资源的占用及性能的损耗。为了优化性能,提升效率,在这种场景中,就应该使用线程池来处理任务。

线程池创建的关键点:
  1. 装载线程的容器,在C++中使用vector
  2. 装载任务的容器,一般使用队列,满足先进先出的特性
  3. 读写任务队列时,需要使用互斥锁,防止多线程读写异常
  4. 线程保活的无限循环中,需要添加一个有任务时运行,无任务时停止的控制器,防止CPU空转。在C++中使用条件变量
  5. 线程启停标识

依据以上关键点,开始编写相应的代码。首次创建线程池类,一般情况下,该类是单例类。

ThreadPool.h

#ifndef THREAD_POOL_H
#define THREAD_POOL_H

#include <thread>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <functional>

class ThreadPool {
    public: 
        static ThreadPool* GetInstance(int number);
        
    private:
        ThreadPool(int number);
        ~ThreadPool();

    public:
        template<typename F, typename... Args>
        void AddTask(F&& func, Args&&... args)
        {
            std::unique_lock<std::mutex> lock(m_Mutex);
            std::function<void()> task = std::bind(std::forward<F> func, std::forward<Args>(args)...);
            m_TaskQueue.emplace(std::move(task));
            lock.unlock();

            m_CV.notify_one();
        }

    private:
        // first: thread container
        // second: task queue
        // third: task queue mutex lock
        // forth: thread keep alive condition varible
        // fifth: thread start/stop flag
        // sixth: storage thread count
        std::vector<std::thread> m_Threads;
        std::queue<std::function<void()>> m_TaskQueue;
        std::mutex m_Mutex;
        std::condition_variable m_CV;
        bool m_IsRunning;
        int m_ThreadNum;
};

#endif
#include "ThreadPool.h"

static ThreadPool *pInstance = nullptr;
static std::once_flag flag1;

ThreadPool *ThreadPool::GetInstance(int number)
{
    std::call_once(flag1, [number](){
        pInstance = new ThreadPool(number);
    });
    return pInstance;
}

ThreadPool::ThreadPool(int number)
    : m_ThreadNum(number), m_IsRunning(true)
{
    m_Threads.push_back(std::thread([this](){
        while (true) // thread keep alive
        {
            std::unique_lock<std::mutex> lock(m_Mutex);
            m_CV.wait(lock, [this](){
                bool isEmpty = m_TaskQueue.empty();
                // task is not empty or thread stopped
                return !isEmpty || !m_IsRunning;
            });

            if (!m_IsRunning)// thread stop
            {
                break;
            }
            auto task = m_TaskQueue.front();
            m_TaskQueue.pop();
            lock.unlock();
            task();
        }
    }));
}

ThreadPool::~ThreadPool()
{
    {
        std::unique_lock<std::mutex> lock(m_Mutex);
        m_IsRunning = false;
    }

    m_CV.notify_all();
    
    for (auto &t : m_Threads)
    {
        if (t.joinable())
        {
            t.join();
        }
    }
}

http://www.kler.cn/a/538870.html

相关文章:

  • PyTorch Profiler 的使用
  • Postman接口测试:postman设置接口关联,实现参数化
  • android selinux 问题
  • 嵌入式工程师面试准备(客观题准备)
  • CLion2024.3.2版中引入vector头文件报错
  • 数据库系统架构与DBMS功能探微:现代信息时代数据管理的关键
  • 如何设置爬虫的延时避免频繁请求?
  • 使用rustDesk搭建私有远程桌面
  • vue+element-ui简洁完美实现ju动漫网站
  • ASP.NET Core托管服务
  • Java 线程池内部任务出异常后,如何知道是哪个线程出了异常
  • 【Python】元组
  • Deepseek访问受限?换种方式轻松使用
  • 22.3、IIS安全分析与增强
  • 【React】实现TagInput输入框,可以输入多个邮箱并校验是否合法
  • Agent论文阅读:NormEnforcement with a Soft Touch: Faster Emergence, Happier Agents
  • 阿里云服务器XShell连接启动java -jar xxx.jar后退出ssh,后端也退出,使用screen 亲测管用!
  • 【Jetson Nano安装gpu版pytroch1.7torchvision0.8.1 in python3.8 跑 Ultralytics YOLO】
  • 关于预训练后训练、LLM和视频大模型相关学习记录
  • 周报1.0
  • 鸿蒙音视频播放器:libwlmedia
  • 如何解决 Linux 文件系统挂载失败的问题
  • vue print 打印
  • 11.递归遍历、迭代遍历、统一迭代、层序遍历
  • Excel大数据量导入导出
  • React 生命周期函数详解