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

学习完C++ 并发编程后 手写线程池 最简单的线程池

目录

精简版注释:

//线程安全的队列容器(精简版)  

 最简易可行的线程池(精简版)

详细版注释:

//线程安全的队列容器(详细版) 

最简易可行的线程池(详细版)

ThreadRAII.h


参考:《C++并发编程实战 第二版》Anthony Willams著 吴天明 译

在学习完这本书后想要提高一下编码能力。

可以先参考精简版的注释,尝试写一写代码,感觉有难度的话就参考详细版。

具体代码和个人遇到的一些问题可以参考我的下一篇博客。

精简版注释:

//线程安全的队列容器(精简版)  

//实现线程安全的队列容器(通过封装一个queue)
//成员变量:
//      1.通过mutex互斥对pop、push操作加锁,从而实现“安全”
//      2.内部封装的queue,queue容器内部存储share_ptr,数据通过share_ptr间接存储好处:
//              将每个数据的share_ptr初始化放在push()中,wait_and_pop就算异常安全的
//              对share_ptr实例分配内存的操作可以脱离锁的保护,有利于增强性能
//      3.条件变量等待条件成立(pop之前必须先push)
//成员函数:
//      1.构造函数
//      2.push
//      3.pop 通过函数参数传递要pop的数据:
//              两种pop,try_pop立即返回,即使队列为空(通过返回值表示操作失败)
//              wait_and_pop 一直等到有数据才pop
//      4.通过返回值传递要pop的数据
//      5.empty
//
 

 最简易可行的线程池(精简版)

//成员变量:
//      1.监控异常的原子变量
//      2.线程安全的工作队列
//      3.工作线程
//      4.封装好的能够join线程的线程类
//      5.work_thread() 当线程池能正常工作时就一直循环执行任务

//公有成员:
//      1.构造函数
//      thread_pool():将监控异常的原子变量设置为false,
//              join_threads用工作线程vector初始化
//      {
//      }
//      2.析构函数
//      {
//       将原子变量设置为true,避免线程池销毁后,工作线程还在循环申请任务
//      }
//      3.提交线程函数(函数模板)
//      {
//              把待处理的任务(函数)提交给任务队列
//      }
//

详细版注释:

//线程安全的队列容器(详细版) 

//实现线程安全的队列容器(通过封装一个queue)
//成员变量:
//      1.通过mutex互斥对pop、push操作加锁,从而实现“安全”
//      2.内部封装的queue,queue容器内部存储share_ptr,数据通过share_ptr间接存储好处:
//              将每个数据的share_ptr初始化放在push()中,wait_and_pop就算异常安全的
//              对share_ptr实例分配内存的操作可以脱离锁的保护,有利于增强性能
//      3.条件变量等待条件成立(pop之前必须先push)
//成员函数:
//      1.构造函数
//      2.push{1.为数据创建share_ptr指针    //通过move移动操作降低开销2.互斥上锁3.队列push数据4.条件变量通知有数据}
//      3.pop 通过函数参数传递要pop的数据:
//           bool try_pop(T& value) //立即返回,即使队列为空(通过返回值表示操作失败){    //pop操作都是要操作队列的,所以一开始就要上锁,没有操作能提取到互斥之外1.互斥上锁2.判断是否为空队列 if(空) return false;else(不空) {1.队头数据传给value    //通过move移动操作降低开销2.队列pop3.return true;}}
//            void wait_and_pop(T& value) //一直等到有数据才pop{    //pop操作都是要操作队列的,所以一开始就要上锁,没有操作能提取到互斥之外1.互斥上锁;2.通过条件变量等待条件发生,通过lambda表达式保证即使被条件变量唤醒了,也要保证队列非空才能进行pop操作;3.对头数据传给value;4.队列pop               }
//      4.通过返回值传递要pop的数据:std::shared_ptr<T> try_pop(){    //pop操作都是要操作队列的,所以一开始就要上锁,没有操作能提取到互斥之外1.互斥上锁;2.判断是否为空队列 if(空) return nullptr;else(不空){1.临时变量取得队头数据2.队列pop3.return 临时变量}}std::shared_ptr<T> wait_and_pop(){    //pop操作都是要操作队列的,所以一开始就要上锁,没有操作能提取到互斥之外1.互斥上锁2.通过条件等待条件发生,通过lambda表达式保证即使被条件变量唤醒了,也要保证队列非空才能进行pop操作;3.临时变量取得对头数据4.队列pop5.return 临时变量}
//      5. bool empty() const{    //函数声明为const 要求将mutex 声明为mutable1.互斥上锁2.返回 封装队列的empty();}
//

最简易可行的线程池(详细版)

#ifndef _THREAD_POOL_EASY_HPP_
#define _THREAD_POOL_EASY_HPP_
#include "ThreadRAII" //join_threads
#include "threadsafe_queue"    //   
//最简单的线程池::工作线程数目固定,当有任务要处理时就把他放进任务队列
//所以需要一个任务队列,用threadsafe_queue来实现
//各线程从任务队列中领取任务
//工作线程存储在vector容器中,并被引用到join_threads中,进行统一的析构管理
//
//私有成员:
//      1.线程的启动可能抛出异常,所以需要一个原子变量进行标识,
//      当该变量false时,线程池正常工作
//              每当有异常抛出时,设置为true 
//              线程池析构时,也设置为true,
//              保证线程池析构后工作线程不会继续循环尝试从工作队列中获取任务
//      2.线程安全的工作队列
//      3.使用vector容器存放工作线程
//      4.封装好的能够join线程的线程类join_threads 里面存的是工作线程vector的整个引用 
//      5.work_thread() 当线程池能正常工作时就一直循环执行任务
//              {
//                      while(线程池正常工作)
//                      {
//                              临时变量用来接收任务
//                              if(工作队列能pop出任务)
//                                      执行任务;
//                              else 
//                                      将cpu时间让给其他线程;
//                      }
//              }
//公有成员:
//      1.构造函数
//      thread_pool():将监控异常的原子变量设置为false,
//              join_threads用工作线程vector初始化
//      {
//              通过std::thread::hardware_concurrency()取得最大线程数
//              try
//              { //线程启动可能抛出异常,所以用try catch包住
//                      for(最大线程数)
//                      {
//                              工作线程放到存放工作线程的vector里
//                      }
//              }
//              catch(...){
//                      出现异常将原子变量设置为true;
//                      throw;
//              }
//      }
//      2.析构函数
//      {
//       将原子变量设置为true,避免线程池销毁后,工作线程还在循环申请任务
//      }
//      3.提交线程函数(函数模板)
//      {
//              把待处理的任务(函数)提交给任务队列
//      }
//#endif

ThreadRAII.h

还需要封装thread类,使std::thread对象在所有路径皆不可联结:详细请参考本书第八章或effective modren C++ 条款37

#ifndef _THREADRAII_H_
#define _THREADRAII_H_//通过封装thread类,使std::thread对象在所有路径皆不可联结
// 详细参见 effective modren C++ 条款37
#include <vector>
#include <thread>
class join_threads
{private:std::vector<std::thread>& threads;public:explicit join_threads(std::vector<std::thread>& threads_):threads(threads_) {}~join_threads(){for(unsigned long i =0; i<threads.size(); i++){if(threads[i].joinable()){threads[i].join();}else{threads[i].detach();}}}
};
#endif

相关文章:

学习完C++ 并发编程后 手写线程池 最简单的线程池

目录 精简版注释&#xff1a; //线程安全的队列容器&#xff08;精简版&#xff09; 最简易可行的线程池&#xff08;精简版&#xff09; 详细版注释&#xff1a; //线程安全的队列容器&#xff08;详细版&#xff09; 最简易可行的线程池&#xff08;详细版&#xff0…...

【Overload游戏引擎分析】编辑器对象鼠标拾取原理

Overload的场景视图区有拾取鼠标功能&#xff0c;单击拾取物体后会显示在Inspector面板中。本文来分析鼠标拾取这个功能背后的原理。 一、OpenGL的FrameBuffer 实现鼠标拾取常用的方式有两种&#xff1a;渲染id到纹理、光线投射求交。Overload使用的是渲染id到纹理&#xff0c…...

【Spring内容进阶 | 第三篇】AOP进阶内容

前言&#xff1a; 在前面我们已经粗略的介绍了什么是AOP以及各种基础知识点&#xff0c;而本篇我们将聚焦于AOP的细节&#xff0c;详细的讲解一下AOP中的通知类型&#xff0c;通知顺序&#xff0c;切入点表达式以及连接点。通过对AOP的熟练掌握&#xff0c;我们可以快速编写出低…...

华为云ModelArts:引领AI艺术创作的未来,让人人都可以成为“艺术家”!

随着科技的飞速发展,艺术创作逐渐告别传统的画布和画笔,开始走向数字化、智能化的新时代。在这个蓬勃发展的领域中,华为云ModelArts以其强大的功能和出色的性能引领着AI艺术创作的未来。 华为云ModelArts是面向开发者的一站式AI开发平台,为机器学习与深度学习提供海量数据预处…...

Elasticsearch:如何从 Elasticsearch 集群中删除数据节点

Elasticsearch 集群通常包含多个节点&#xff0c;并且可能存在需要从集群中删除节点的情况。 应谨慎执行此过程&#xff0c;以确保数据的完整性和可用性。 在本文中&#xff0c;我们将引导你完成从 Elasticsearch 集群安全删除节点的步骤。 确保集群是绿色的 在尝试从 Elastic…...

长假回归,回顾一下所有的电商API接口

淘宝API接口 item_get 获得淘宝商品详情item_get_pro 获得淘宝商品详情高级版item_review 获得淘宝商品评论 获取测试keyitem_fee 获得淘宝商品快递费用item_password 获得淘口令真实urlitem_list_updown 批量获得淘宝商品上下架时间seller_info 获得淘宝店铺详情item_search…...

认识计算机主板

目录 定义主要部件简单图示 主要功能 定义 计算机主板&#xff08;Motherboard&#xff09;是计算机系统中的核心组件之一&#xff0c;也被称为系统板、主板或母板。它是一个电子电路板&#xff0c;用于连接和支持计算机的各种硬件组件&#xff0c;包括中央处理器&#xff08;…...

PHP乱七八糟面试题

1、请解释PHP中的JWT是什么&#xff1f; JWT&#xff08;JSON Web Token&#xff09;是一种用于认证和授权的标准&#xff0c;可以在不同的系统之间安全地传递信息。 在PHP中&#xff0c;可以使用各种JWT库来生成和解析JWT&#xff0c;JWT包含了一些元数据和签名&#xff0c; …...

pom管理规范

0. 引言 在单机架构下&#xff0c;我们只需要将我们的依赖在pom中引入。但是过渡到微服务架构后&#xff0c;会涉及到多模块引用相同的依赖&#xff0c;多模版之间依赖的版本太过分散难以管理的问题。 这就需要我们利用maven中依赖传递的特性&#xff0c;结合dependencyManage…...

AI大模型的安全隐患问题与新兴Anthropic新势力涌动

引言&#xff1a; 无论从社会层面或技术层面&#xff0c;大模型的安全隐患都是一个不容小觑的话题。也正因此&#xff0c;ChatGPT 初兴起时&#xff0c;国内的 To C 大模型产品一时受阻。而尽管 9 月初第一批 8 家大模型通过备案&#xff0c;各家厂商对大模型的安全问题也不敢…...

slamplay:用C++实现的SLAM工具集

0. 项目简介 slamplay 是一个功能强大的工具集合&#xff0c;可用于开始使用 C 来玩和试验 SLAM。这是一项正在进行的工作。它在单个 cmake 框架中安装并提供一些最重要的功能 后端框架&#xff08;g2o、gtsam、ceres、se-sync 等&#xff09;、 前端工具&#xff08;opencv、…...

IPT2602协议-USB 快速充电端口控制器

产品描述&#xff1a; IPT2602是一款USB端口快速充电协议控制芯片。IPT2602智能识别多种快速充电协议&#xff0c;对手机等受电设备进行快速充电。IPT2602根据受电设备发送的电压请求能够精确的调整VBUS输出电压&#xff0c;从而实现快速充电。 IPT2602在调整5V输出电压前会自动…...

Zotero 超好用插件的下载链接及配置方法(PDF-translate/ZotFile/茉莉花/Zotero Scihub)

目录 前言插件安装方法插件一&#xff1a;文献翻译插件&#xff08;pdf-translate&#xff09;插件二&#xff1a;文献附件管理&#xff08;ZotFile&#xff09;插件三&#xff1a;中文文献插件&#xff08;茉莉花&#xff09;插件四&#xff1a;Sci-Hub 自动下载文献&#xff…...

Titus网关中的缓存一致性机制

API网关引入缓存可以在不影响数据一致性的前提下&#xff0c;有效优化接口时延。本文介绍了Netflix在Titus网关上引入缓存的实践&#xff0c;比较了有无缓存对访问时延的影响。原文: Consistent caching mechanism in Titus Gateway 前言 Titus是Netflix的云容器运行时&#xf…...

flutter开发实战 - inappwebview设置cookie

flutter开发实战-inappwebview设置cookie 在使用inappwebview时候&#xff0c;需要设置cookie&#xff0c;这里记录一下 一、在initialUserScripts中设置cookie 在inappwebview中有一个initialUserScripts&#xff0c;可以初始化设置cookie等&#xff0c;我们可以通过该属性…...

零基础如何自学网络安全,基于就业前景全方位讲解,包教包会

你是否对网络空间安全充满好奇&#xff1f;想要解开网络世界神秘的面纱&#xff1f;你是否对黑客技术着迷&#xff1f;而找不到合适的学习途径&#xff1f;你是否遭到过各种各样的网络攻击&#xff0c;却因知识的匮乏束手无策&#xff1f; 那么接下来将为你全面介绍&#xff0c…...

Java项目防止SQL注入的几种方案

目录 一、什么是SQL注入&#xff1f; 二、Java项目防止SQL注入方式 1、PreparedStatement防止SQL注入 2、mybatis中#{}防止SQL注入 3、对请求参数的敏感词汇进行过滤 4、nginx反向代理防止SQL注入 一、什么是SQL注入&#xff1f; SQL注入即是指web应用程序对用户输入数…...

Win11 安装安卓子系统方法教程

WIN11安装安卓子系统 准备工作下载安装安装完成使用adb连接子系统结束 准备工作 开启电脑中的 控制面板>>>>程序和功能>>启用或关闭Windows功能>>>找到“Hyper-V”&#xff0c;把勾都勾上&#xff0c;确定&#xff0c;完成安装&#xff0c;并重启电…...

golang pg 数据库不存在 就创建 --chatPGT

问&#xff1a;linkOrCreateDatabase(addr ), 函数执行 连接 pg数据库&#xff0c;若数据库 不存在就创建 gpt: 要在 Go 中连接到 PostgreSQL 数据库并在数据库不存在时创建数据库&#xff0c;你可以使用 github.com/lib/pq 包以及 database/sql 包。以下是一个示例&#xff1…...

VUE3照本宣科——eslint与prettier

VUE3照本宣科——eslint与prettier VUE3照本宣科系列导航 前言一、eslint1.配置文件2.配置规则3.忽略错误 二、prettier三、总结 VUE3照本宣科系列导航 1.VUE3照本宣科——认识VUE3 2.VUE3照本宣科——应用实例API与setup 3.VUE3照本宣科——响应式与生命周期钩子 4.VUE3照本宣…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...

日常一水C

多态 言简意赅&#xff1a;就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过&#xff0c;当子类和父类的函数名相同时&#xff0c;会隐藏父类的同名函数转而调用子类的同名函数&#xff0c;如果要调用父类的同名函数&#xff0c;那么就需要对父类进行引用&#…...

通过MicroSip配置自己的freeswitch服务器进行调试记录

之前用docker安装的freeswitch的&#xff0c;启动是正常的&#xff0c; 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...

十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建

【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...

SQL Server 触发器调用存储过程实现发送 HTTP 请求

文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...

FOPLP vs CoWoS

以下是 FOPLP&#xff08;Fan-out panel-level packaging 扇出型面板级封装&#xff09;与 CoWoS&#xff08;Chip on Wafer on Substrate&#xff09;两种先进封装技术的详细对比分析&#xff0c;涵盖技术原理、性能、成本、应用场景及市场趋势等维度&#xff1a; 一、技术原…...