线程池C++11实现

news/2024/12/15 17:47:48/文章来源:https://www.cnblogs.com/runtimeerror/p/18608240

设计思路

tasks: 任务队列,每当有新任务时,就addTask到该队列

workers: 工作线程,不断地从tasks中取任务执行

queueMutex: 任务队列互斥锁,防止在addTask时出现冲突

condition_variable: 条件变量,当任务队列为空时阻塞线程,等待任务被添加进队列

function<void()> : 函数对象,tasks队列的成员,当前每一个都可以当成返回值为void、无参数的函数执行,由于后续添加任务时多数是带有返回值和参数的,因此需要使用bind函数绑定所有参数适配成void()类型,使用future获取所添加的任务返回值

实现步骤

整体结构

class ThreadPool
{using Task = std::function<void()>;public:explicit ThreadPool(size_t threads);template <class F, class... Args>auto addTask(F&& f, Args&& ...args)->std::future<std::result_of_t<F(Args...)>>; // 类型后置,获取返回值void stop();~ThreadPool();private:std::vector<std::thread> _workers;std::queue<Task> _tasks;std::mutex _queueMutex;std::condition_variable _cv;bool _stop;
private:void executeTask();
};

初始化

创建指定数量的线程,每个线程负责执行excuteTask函数(不断取任务执行)

ThreadPool::ThreadPool(size_t threads): _stop(false)
{for (int i = 0; i < threads; ++i){_workers.emplace_back(&ThreadPool::executeTask,this);}
}

执行任务

不断从tasks队列取任务并执行,由于同时会有多个线程读写tasks队列会出现冲突,因为需要加锁,使用条件变量,当tasks队列为空时阻塞线程,如果线程池停止(stop=true)同时队列为空则整个线程终止.

void ThreadPool::executeTask()
{while (true){std::unique_lock<std::mutex> lock{_queueMutex};_cv.wait(lock,[this]{return _stop || !(_tasks.empty());});if (_stop && _tasks.empty())return;auto task = std::move(_tasks.front());_tasks.pop();lock.unlock();task();}
}

添加任务

可变参数模板

该语法支持添加任意数目参数的函数,通过执行f(args...)可执行添加的任务函数。可以使用bind函数绑定f函数和它的所有参数,将其转换成无参的task函数对象(由于fun函数形参是&&,右值引用型,故需用到forward函数,详细请搜索右值引用)

template<class F, class... Args>
ret fun(F&& f, Args&& ...args){std::funtion<void()> task = std::bind(std::forward<F>(f), std::forward<Args>(args)...);.....
}

decltype可以根据变量推测出类型。

添加任务到tasks队列,加锁防止冲突

template <class F, class... Args>
auto ThreadPool::addTask(F&& f, Args&& ...args) ->std::future<std::result_of_t<F(Args...)>>
{using RetType = decltype(f(args...));auto task = std::make_shared<std::packaged_task<RetType()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));std::future<RetType> ret_future = task->get_future();std::unique_lock<std::mutex> lock{_queueMutex};    if (_stop){throw std::runtime_error("the threadPool is stopped.");}// 添加任务到任务队列_tasks.emplace([task] {(*task)();});lock.unlock();_cv.notify_one();return ret_future;
}

停止线程池

将_stop置为true,同时将workers中所有线程执行完毕,即可停止线程池

void ThreadPool::stop()
{std::unique_lock<std::mutex> lock(_queueMutex);_stop = true;lock.unlock();for (auto &t : _workers){if (t.joinable())t.join();}
}

完整代码

#ifndef THREADPOOL_H
#define THREADPOOL_H
#include <queue>
#include <vector>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <thread>
#include <iostream>
#include <future>
#include <memory>
class ThreadPool
{using Task = std::function<void()>;public:explicit ThreadPool(size_t threads);template <class F, class... Args>auto addTask(F&& f, Args&& ...args)->std::future<std::result_of_t<F(Args...)>>; // 类型后置,获取返回值void stop();~ThreadPool();private:std::vector<std::thread> _workers;std::queue<Task> _tasks;std::mutex _queueMutex;std::condition_variable _cv;bool _stop;
private:void executeTask();
};ThreadPool::ThreadPool(size_t threads): _stop(false)
{for (int i = 0; i < threads; ++i){_workers.emplace_back(&ThreadPool::executeTask,this);}
}// add task for work_queue
template <class F, class... Args>
auto ThreadPool::addTask(F&& f, Args&& ...args) ->std::future<std::result_of_t<F(Args...)>>
{using RetType = decltype(f(args...));auto task = std::make_shared<std::packaged_task<RetType()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));std::future<RetType> ret_future = task->get_future();std::unique_lock<std::mutex> lock{_queueMutex};    if (_stop){throw std::runtime_error("the threadPool is stopped.");}// 添加任务到任务队列_tasks.emplace([task] {(*task)();});lock.unlock();_cv.notify_one();return ret_future;
}// _stop the thread_pool
inline void ThreadPool::stop()
{std::unique_lock<std::mutex> lock(_queueMutex);_stop = true;lock.unlock();for (auto &t : _workers){if (t.joinable())t.join();}
}// exectuTask
void ThreadPool::executeTask()
{while (true){std::unique_lock<std::mutex> lock{_queueMutex};_cv.wait(lock,[this]{return _stop || !(_tasks.empty());});if (_stop && _tasks.empty())return;auto task = std::move(_tasks.front());_tasks.pop();lock.unlock();task();}
}ThreadPool::~ThreadPool()
{stop();
}#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/853370.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NAS部署quark-auto-save,实现网盘资源自由

安装拉取镜像docker pull cp0204/quark-auto-save:latest一键运行容器docker run -d--name quark-auto-save-p 5005:5005-e TZ=Asia/Shanghai-v /volume1/docker/quark-auto-save:/app/config # 配置文件路径--restart unless-stoppedcp0204/quark-auto-save:latest系统配置首次…

索引与性能优化

title: 索引与性能优化 date: 2024/12/15 updated: 2024/12/15 author: cmdragon excerpt: 索引是数据库性能优化的重要工具,通过建立索引,可以加速数据的检索和查询操作,从而提高数据库的响应速度。虽然索引能显著改善数据访问性能,但不当的使用也可能导致性能下降。 ca…

Differential Transformer: 通过差分注意力机制提升大语言模型性能

Transformer模型已经成为大语言模型(LLMs)的标准架构,但研究表明这些模型在准确检索关键信息方面仍面临挑战。今天介绍一篇名叫Differential Transformer的论文,论文的作者观察到一个关键问题:传统Transformer模型倾向于过分关注不相关的上下文信息,这种"注意力噪声…

idea简单调试

1.行断点是一个小红原点 然后,在main方法中点击调试,程序运行时会在该点停顿,点击 恢复程序就会继续运行2.详细断点 | 源断点 shift+左键唤出断点是一个小黄圆点,并且有一些信息 若点击挂起再点完成,将会变为小红圆点 点击调试,控制台给出断点位置 3.方法断点 是一个小…

30KW储能PCS逆变器双向变流器设计方案

本方案介绍了一款30KW储能PCS逆变双向变流器方案,是双向DCDC的以及三电平逆变PCS技术。此方案包含了原理图(PDF)格式的,包含控制板,滤波板,DCDC模块以及逆变板。本方案是DSP+CPLD的控制架构,DSP是德州仪器(TI)TMS320F28234PGFA,CPLD是Altera的EPM240T100I5。两个处理…

数据采集大作业

这个项目属于哪个课程2024数据采集与融合技术实践 组名 从你的全世界爬过团队logo:项目简介 项目名称:博物识植项目logo:项目介绍:在探索自然奥秘的旅途中,我们常与动植物相伴而行,却无法准确识别它们,更难以深入了解他们的特征。为了更好地理解和欣赏自然界的多样性,…

SpringBoot——使用http2

使用http2许多浏览器,包括Edge,仅在TLS(即HTTPS)情况下支持HTTP/2。即使服务器端配置为无TLS支持的HTTP/2,浏览器可能仍将回退到HTTP/1.1。所以我们需要有一个证书来开启https。生成自签名证书 使用JDK的keytool工具生成自签名证书。 keytool -genkeypair -alias myalias …

一文学懂Catboost模型

参考: 深入理解CatBoost - 知乎 20240322-2-Catboost面试题-CSDN博客 ​这次终于彻底理解了 CatBoost 原理及应用 豆包大模型

深度强化学习基础(王树森) 1 基本概念

概率论 随机变量:值取决于随机事件的结果 大写字母\(X\)表示随机变量,小写字母\(x\)表示随机变量的观测值 概率密度函数(Probability Density Function, PDF):随机变量在某个确定的取值点附近的可能性连续 or 离散期望: \(p(x)\)为概率密度函数术语 状态(state) 动作(…

bc 与 hbm 一致性比对

01 引言 使用地平线 征程 6 算法工具链时,算法侧在验证 quantized.bc 精度符合预期后,软件侧反馈 hbm 精度不符合预期,此时应该怎么做呢?(“打一架!”) 对于熟悉地平线算法工具链的用户而言,可能会立刻想到,使用 hb_verifier 工具比对 bc 与 hbm 的一致性即可,so eas…

Python3虚拟机和对象

2024年最推荐的python3版本为3.11 python虚拟机和对象 Python对象和虚拟机_v4.pdf Python虚拟机的原理 • 字节码生成 • 虚拟机运行 Python对象的实现 • 数据结构 • 类型系统 • 内存管理 Python虚拟机字节码和机器码有什么区别 字节码和机器码是计算机程序执行的两种不同形…

Buffer

Buffer(缓冲器)1. 概念 Buffer 是一个类似于数组的 对象 ,用于表示固定长度的字节序列 Buffer 本质是一段内存空间,专门用来处理 二进制数据 。2. 特点 1. Buffer 大小固定且无法调整 2. Buffer 性能较好,可以直接对计算机内存进行操作 3. 每个元素的大小为 1 字节(byte)…