4.采用锁操作并支持等待功能的线程安全队列
分析
书接上文
修改push()似乎并不困难:在函数末尾加上对data_cond.notify_one()的调用即可,与代码清单1(第一篇文章)一样。事情其实没那么简单,我们之所以采用精细粒度的锁,目的是尽可能提高并发操作的数量。如果在notify_one()调用期间,互斥依然被锁住,形式与代码清单1一样,而等待通知的线程却在互斥解锁前觉醒,它就需要继续等待互斥解锁。矛盾的是,若在解锁互斥之后调用notify_one(),那么互斥已经可以再次获取,并且超前一步,等着接受通知的线程对其加锁(前提是其他线程没有抢先将其重新锁住)。这点改进看似细微,但对某些情况却有重要作用。
wait_and_pop()就复杂得多,因为我们需要确定在哪里等待、根据什么断言唤醒等待、需要锁住什么互斥等。等待唤醒的条件是“队列非空”,用代码表示为 head!=tail。
按这种写法,要求两个互斥head_mutex和 tail_mutex 都被锁住,我们分析代码清单3(第三篇文章)的时候就已经确定,只有在读取 tail 指针时才有必要锁住互斥tai_mutex,而比较运算无须保护,本例同理。若我们将断言设定为head!=get_tail(),则只需持有互斥 head_mutex,所以在调用 data_cond.wait()时,就可以重新锁住head_mutex。只要我们加入了等待的逻辑,这种实现就与 try_pop()一样。
对于try_pop()的另一个重载和对应的 wait_and_pop() 的重载,我们也要谨慎思考和设计。在代码清单3中,try_pop()函数的结果通过共享指针std::shared_ptr的实例返回,其指向目标由old_head间接从 pop_head() 取得。如果模仿代码清单1,将以上方法改为 try_pop()的第一个重载的模式,令函数接收名为value 的引用参数,再由拷贝赋值操作赋予它 old_head 的值,就可能会出现与异常有关的问题。根据这种改动,在拷贝赋值操作执行时,数据已经从队列中移除,且互斥已经解锁,剩下的全部动作就是将数据返回给调用者。但是,如果拷贝赋值操作抛出了异常(完全有可能),则该项数据丢失,因为它无法回到队列本来的位置上。
若队列模板在具现化时,模板参数采用了实际类型T,而该类型支持不抛出异常的移动赋值操作,或不抛出异常的交换操作,我们即可使用类型T。然而,我们还是更希望实现通用的解决方法,对任何类型T都有效。在上述场景中,我们需要在队列移除节点以前,将可能抛出异常的操作移动到锁的保护范围之内。也就是说,我们还需要pop_head()的另一个作用,在改动队列之前就获取其存储的值。
相比而言,empty(就很简单了:只需锁住互斥head_mutex,然后检查 head_get_tail()。
一、实现
接口
template<typename T>
class threadsafe_queue{
private:struct node{std::shared_ptr<T> data;std::unique_ptr<node> next;};std::mutex head_mutex;std::unique_ptr<node> head;std::mutex tail_mutex;node* tail;std::condition_variable data_cond;
public:threadsafe_queue():head(new node),tail(head.get()){}threadsafe_queue(const threadsafe_queue& other)=delete;threadsafe_queue& operator=(const threadsafe_queue& other)=delete;std::shared_ptr<T> try_pop();bool try_pop(T& value);std::shared_ptr<T>wait_and_pop();void wait_and_pop(T& value);void push(T new_value);bool empty();
];
压入新数据
template<typename T>{void threadsafe_queue<T>::push(T new_value)std::shared_ptr<T> new_data(std::make_shared<T>(std::move(new_value)));std::unique_ptr<node>p(new node);{std::lock_guard<std::mutex> tail_lock(tail_mutex);tail->data=new_data;node* const new_tail=p.get();tail->next=std::move(p);tail=new_tail;}data_cond.notify_one();
}
我们提过,复杂之处全在于pop()上,我们运用几个辅助函数简化操作。
template<typename T>
class threadsafe_queue{
private :node* get_tail(){std::lock_guard<std::mutex> tail_lock(tail mutex);return tail;}std::unique_ptr<node> pop_head()①{std::unique_ptr<node> old_head=std::move(head);head=std::move(old_head->next);return old_head;}std::unique_lock<std::mutex> wait_for_data()②{std::unique_lock<std::mutex> head_lock(head_mutex);data_cond.wait(head_lock,[&]{return head.get()!=get_tail();));return std::move(head_lock);③}std::unique_ptr<node> wait_pop_head(){std::unique_lock<std::mutex> head_lock(wait_for_data());④return pop_head();}std::unique ptr<node> wait_pop_head(T& value){std::unique_lock<std::mutex>head_lock(wait_for_data());⑤value=std::move(*head->data);return pop head();}
public:std::shared ptr<T> wait_and_pop(){std::unique_ptr<node> const old_head=wait_pop_head();return old_head->data;}void wait_and_pop(T& value){std::unique_ptr<node> const old_head=wait_pop_head(value);}
};
这里展示出 wait_and_pop()实现代码,它含有几个辅助函数,用以简化代码和减少重复,如 pop_head()①和 wait_for_data()②。前者移除头节点而改动队列,后者则等待数据加入空队列,以将其弹出。wait_for_data()特别值得注意,它在条件变量上等待,以 lambda 函数作为断言,并且向调用者返回锁的实例③。因为 wait pop_head()的两个重载都会改动队列数据,并且都依赖wait_for_data()函数,而后者将锁返回则保证了头节点弹出的全过程都持有同一个锁④⑤。这也为里的 pop_head()和ty_pop()使用。
template<typename T>
class threadsafe_queue
private:std::unique_ptr<node> try_pop_head(){std::lock guard<std::mutex> head lock(head_mutex);if(head.get()==get_tail()){return std::unique_ptr<node>();}return pop_head();}std::unique_ptr<node> try_pop_head(T& value){std::lock guard<std::mutex> head_lock(head_mutex)if(head.get()==get_tail()){return std::unique_ptr<node>();}value=std::move(*head->data);return pop_head()}
public:std::shared ptr<T> try_pop(){std::unique_ptr<node> old_head=try_pop_head();return old_head?old_head->data:std::shared_ptr<T>();}bool try_pop(T& value){std::unique ptr<node> const old_head=try_pop_head(value);return old_head!=nullptr;}bool empty(){std::lock_guard<std::mutex> head_lock(head_mutex);return(head.get()==get_tail());}
);
总结
相关文章:
4.采用锁操作并支持等待功能的线程安全队列
分析 书接上文 修改push()似乎并不困难:在函数末尾加上对data_cond.notify_one()的调用即可,与代码清单1(第一篇文章)一样。事情其实没那么简单,我们之所以采用精细粒度的锁,目的是尽可能提高并发操作的数量。如果在notify_one()调用期间&a…...
螺杆支撑座在运用中会出现哪些问题?
螺杆支撑座是一种用于支撑滚珠螺杆的零件,通常用于机床、数控机床、自动化生产线等高精度机械设备中。在运用中可能会出现多种问题,这些问题源于多个方面,以下是对可能出现的问题简单了解下: 1、安装不当:安装过程中没…...
OSI 七层模型 | TCP/IP 四层模型
注:本文为 “OSI 七层模型 | TCP/IP 四层模型” 相关文章合辑。 未整理去重。 OSI 参考模型(七层模型) BeretSEC 于 2020-04-02 15:54:37 发布 OSI 的概念 七层模型,亦称 OSI(Open System Interconnection…...
秒鲨后端之MyBatis【2】默认的类型别名、MyBatis的增删改查、idea中设置文件的配置模板、MyBatis获取参数值的两种方式、特殊SQL的执行
别忘了请点个赞收藏关注支持一下博主喵!!!! ! ! 下篇更新: 秒鲨后端之MyBatis【3】自定义映射resultMap、动态SQL、MyBatis的缓存、MyBatis的逆向工程、分页插件。 默认的类型别名 MyBatis的增删改查 添加 <!--int insertUs…...
快云服务器小助手getdetail存在任意文件文件读取漏洞
免责声明: 本文旨在提供有关特定漏洞的深入信息,帮助用户充分了解潜在的安全风险。发布此信息的目的在于提升网络安全意识和推动技术进步,未经授权访问系统、网络或应用程序,可能会导致法律责任或严重后果。因此,作者不对读者基于本文内容所采取的任何行为承担责任。读者在…...
尚硅谷Vue3入门到实战 —— 02 编写 App 组件
根目录下的 index.html 是项目的入口文件,默认的具体内容如下: src 文件夹分析 <!DOCTYPE html> <html lang""><head><meta charset"UTF-8"><link rel"icon" href"/favicon.ico"&…...
Java - 日志体系_Simple Logging Facade for Java (SLF4J)日志门面_SLF4J实现原理分析
文章目录 官网SLF4J 简单使用案例分析SLF4J 获取 Logger 的原理获取 ILoggerFactory 的过程获取 Logger 的过程SLF4J 与底层日志框架的集成 小结 官网 https://slf4j.org/ Simple Logging Facade for Java (SLF4J) 用作各种日志记录框架(e.g…...
Flutter 调试环境下浏览器网络请求跨域问题解决方案
本篇文章主要讲解,Flutter调试环境情况下,浏览器调试报错跨域问题的解决方法,通过本篇文章你可以快速掌握Flutter调试环境情况下的跨域问题。 日期:2024年12月28日 作者:任聪聪 报错现象: 报文信息…...
python编译为可执行文件
1.用py2exe生成可执行文件 目前,在py2exe 0.9.2版本已经支持python3.x,它可以将python程序打包为windows下独立的可执行文件。 要使用py2exe,首先要编写一个编译程序(例如编写一个名为setup.py的程序),然后在python中运行…...
【机器学习(九)】分类和回归任务-多层感知机(Multilayer Perceptron,MLP)算法-Sentosa_DSML社区版 (1)111
文章目录 一、算法概念111二、算法原理(一)感知机(二)多层感知机1、隐藏层2、激活函数sigma函数tanh函数ReLU函数 3、反向传播算法 三、算法优缺点(一)优点(二)缺点 四、MLP分类任务…...
spring cloud微服务-OpenFeign的使用
OpenFeign的使用 openFeign的作用是服务间的远程调用 ,比如通过OpenFeign可以实现调用远程服务。 已经有了LoadBalancer为什么还要用openFeign? 在微服务架构中,LoadBalancer和OpenFeign虽然都提供了服务间调用的能力,但它们的设计目的和…...
欢迪迈手机商城设计与实现基于(代码+数据库+LW)
摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本欢迪迈手机商城就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息…...
GCP Cloud Architect exam - PASS
备考指南 推荐视频课程 https://www.udemy.com/course/google-cloud-architect-certifications/?couponCodeKEEPLEARNING 推荐题库 https://www.udemy.com/course/gcp-professional-cloud-architect-exam-practice-tests-2024/?couponCodeKEEPLEARNING 错题集 http…...
通过 `@Configuration` 和 `WebMvcConfigurer` 配置 Spring MVC 中的静态资源映射
通过 Configuration 和 WebMvcConfigurer 配置 Spring MVC 中的静态资源映射 一、前言1. 了解静态资源的默认配置2. 使用 Configuration 和 WebMvcConfigurer 自定义资源映射示例:将 /upload/ 和 /img/ 映射到不同的文件系统目录解释:为什么使用 classpa…...
敏捷测试文化的转变
敏捷文化是敏捷测试转型的基础,只有具备敏捷文化的氛围,对组织架构、流程和相关测试实践的调整才能起作用。在前面的敏捷测试定义中,敏捷测试是遵从敏捷软件开发原则的一种测试实践,这意味着敏捷的价值观。 此外,从传…...
深度学习:从原理到搭建基础模型
引言: 深度学习为什么火? 深度学习在处理复杂的感知和模式识别任务方面展现出了前所未有的能力。以图像识别为例,深度学习模型(如卷积神经网络 CNN)能够识别图像中的各种物体、场景和特征,准确率远超传统的计算机视觉方法。 当然这之中也还因为 大数据时代的推动(随着…...
MySQL和HBase的对比
Mysql :关系型数据库,主要面向 OLTP ,支持事务,支持二级索引,支持 sql ,支持主从、 Group Replication 架构模型(此处以 Innodb 为例,不涉及别的存储引擎)。 HBase &am…...
Gateway Timeout504 网关超时的完美解决方法
引言 在Web开发中,遇到HTTP状态码504(Gateway Timeout)是相当常见的。这个状态码表示前端服务器(如负载均衡器或代理服务器)作为网关工作时,在尝试访问后端服务器处理请求时未能及时得到响应。本文将探讨导…...
【探花交友】day03—MongoDB基础
目录 课程介绍 1、通用设置 1.1 需求分析 1.2 查询通用设置 1.2 陌生人问题 1.3 通知设置 1.4 黑名单管理 2、MongoDB简介 1.1、MongoDB简介 1.2、MongoDB的特点 1.3 数据类型 3、MongoDB入门 2.1、数据库以及表的操作 2.2、新增数据 2.3、更新数据 2.4、删除数…...
总结-常见缓存替换算法
缓存替换算法 1. 总结 1. 总结 常见的缓存替换算法除了FIFO、LRU和LFU还有下面几种: 算法优点缺点适用场景FIFO简单实现可能移除重要数据嵌入式系统,简单场景LRU局部性原理良好维护成本高,占用更多存储空间内存管理,浏览器缓存L…...
宏集eX710物联网工控屏在石油开采机械中的应用与优势
案例概况 客户:天津某石油机械公司 应用产品:宏集eX710物联网工控屏 应用场景:钻井平台设备控制系统 一、应用背景 石油开采和生产过程复杂,涵盖钻井平台、采油设备、压缩机、分离器、管道输送系统等多种机械设备。这些设备通…...
【社区投稿】自动特征auto trait的扩散规则
自动特征auto trait的扩散规则 公式化地概括,auto trait marker trait derived trait。其中,等号右侧的marker与derived是在Rustonomicon书中的引入的概念,鲜见于Rust References。所以,若略感生僻,不奇怪。 marker …...
【MySQL】第一弹----库的操作及数据类型
笔上得来终觉浅,绝知此事要躬行 🔥 个人主页:星云爱编程 🔥 所属专栏:MySQL 🌷追光的人,终会万丈光芒 🎉欢迎大家点赞👍评论📝收藏⭐文章 一、SQL 语句分类 DDL:数据定…...
【服务器主板】定制化:基于Intel至强平台的全新解决方案
随着数据处理需求不断增长,服务器硬件的发展也在持续推进。在这一背景下,为用户定制了一款全新的基于Intel至强平台的服务器主板,旨在提供强大的计算能力、优异的内存支持以及高速存储扩展能力。适用于需要高性能计算、大规模数据处理和高可用…...
Flutter路由工具类RouteUtils,可二次开发,拿来即用
一、RouteUtils路由核心类 /*** 路由封装*/ class RouteUtils {RouteUtils._();static final navigatorKey GlobalKey<NavigatorState>();// App 根节点Contextstatic BuildContext get context > navigatorKey.currentContext!;static NavigatorState get navigato…...
报错:No module named ‘pygeohash‘
如果你遇到这个错误: platform... using builtin-java classes where applicableTraceback (most recent call last):File "/home/spark-shell/AppLogDWD02.py", line 4, in <module>from pygeohash import encodeModuleNotFoundError: No module …...
SQL中的TRIM用法
TRIM 是 SQL 中用于去除字符串两端(左侧和右侧)的空格或特定字符的函数。这个函数常用于清理数据中的无效空白字符,尤其是在从外部系统导入数据时,常常会遇到数据两端有不必要的空格,使用 TRIM 可以去除这些多余的字符…...
AIGC在电影与影视制作中的应用:提高创作效率与创意的无限可能
云边有个稻草人-CSDN博客 目录 引言 一、AIGC在剧本创作中的应用 1.1 剧本创作的传统模式与挑战 1.2 AIGC如何协助剧本创作 1.3 未来的剧本创作:AI辅助的协同创作 二、AIGC在角色设计中的应用 2.1 传统角色设计的挑战 2.2 AIGC如何协助角色设计 三、AIGC在…...
【蓝桥杯——物联网设计与开发】拓展模块5 - 光敏/热释电模块
目录 一、光敏/热释电模块 (1)资源介绍 🔅原理图 🔅AS312 🌙简介 🌙特性 🔅LDR (2)STM32CubeMX 软件配置 (3)代码编写 (4&#x…...
深入探索openEuler Kernel:操作系统的心脏
title: 深入探索openEuler Kernel:操作系统的心脏 date: ‘2024-12-28’ category: blog tags: openEulerLinux Kernel操作系统性能优化 sig: Kernel archives: ‘2024-12’ author:way_back summary: openEuler Kernel作为openEuler操作系统的核心,扮演…...
Unity3d UGUI如何优雅的实现Web框架(Vue/Rect)类似数据绑定功能(含源码)
前言 Unity3d的UGUI系统与Web前端开发中常见的数据绑定和属性绑定机制有所不同。UGUI是一个相对简单和基础的UI系统,并不内置像Web前端(例如 Vue.js或React中)那样的双向数据绑定或自动更新UI的机制。UGUI是一种比较传统的 UI 系统ÿ…...
【JavaEE进阶】@RequestMapping注解
目录 📕前言 🌴项目准备 🌲建立连接 🚩RequestMapping注解 🚩RequestMapping 注解介绍 🎄RequestMapping是GET还是POST请求? 🚩通过Fiddler查看 🚩Postman查看 …...
Vue.js组件开发-自定义文件上传
在Vue.js中开发自定义文件上传组件,创建一个独立的Vue组件来处理文件选择和上传的逻辑。这个组件可以包含文件选择器、上传进度条、上传状态提示等元素,并根据需要进行自定义。 示例: <template><div class"file-upload"…...
CES Asia 2025的低空经济展区有哪些亮点?
CES Asia 2025(赛逸展)的低空经济展区有以下亮点: • 前沿科技产品展示: 多款新型无人机将亮相,如固定翼无人机和系留无人机的最新型号,其在监测、救援和货物运输等方面功能强大。此外,还有可能…...
公路边坡安全监测中智能化+定制化+全面守护的应用方案
面对公路边坡的安全挑战,我们如何精准施策,有效应对风险?特别是在强降雨等极端天气下,如何防范滑坡、崩塌、路面塌陷等灾害,确保行车安全?国信华源公路边坡安全监测解决方案,以智能化、定制化为…...
Arduino 驱动GY-271(HMC5883L)三轴磁场模块
Arduino 驱动GY-271(HMC5883L)三轴磁场模块 简介特征参数原理图寄存器通信测量步骤接线主要代码结果 简介 HMC5883L 是一种表面贴装的高集成模块,并带有数字接口的弱磁传感器芯片,应用于低成本罗盘和磁场的检测领域。HMC5883L 包…...
ImportError: cannot import name ‘einsum‘ from ‘einops‘
报错: from einops import einsum ImportError: cannot import name einsum from einops 测试代码: python -c "from einops import einsum" 解决方法: pip uninstall einops pip install einops Successfully installed ein…...
GitLab安装及使用
目录 一、安装 1.创建一个目录用来放rpm包 2.检查防火墙状态 3.安装下载好的rpm包 4.修改配置文件 5.重新加载配置 6.查看版本 7.查看服务器状态 8.重启服务器 9.输网址 二、GitLab的使用 1.创建空白项目 2.配置ssh 首先生成公钥: 查看公钥 把上面的…...
攻防世界web第二题unseping
这是题目 <?php highlight_file(__FILE__);class ease{private $method;private $args;function __construct($method, $args) {$this->method $method;$this->args $args;}function __destruct(){if (in_array($this->method, array("ping"))) {cal…...
Bitmap(BMP)图像信息验证
Bitmap BMP图像信息验证 参考文章例程目的一、Bitmap图像结构二、获取文件大小三、获取应用程序路径四、获取目录中所有内容(包括子目录)五、Bitmap图像信息验证六、主函数测试七、测试结果 参考文章 在Windows下C语言获取当前应用程序运行路径并获取指定目录下所有文件Bitmap…...
Faster R-CNN
文章目录 摘要Abstract1. 引言2. 框架2.1 RPN2.1.1 网络结构2.1.2 损失函数2.1.3 训练细节 2.2 训练过程 3. 创新点和不足3.1 创新点3.2 不足 参考总结 摘要 Faster R-CNN是针对Fast R-CNN缺点改进的目标检测模型。为了解决候选区域生成耗时长的问题,Faster R-CNN提…...
MySQL数据库锁
MySQL中读写不互斥(前提是没有使用串行化隔离级别),但是写写操作要互斥才行,MySQL中使用锁机制来实现写写互斥。 按照锁的粒度可以分为:全局锁、表锁、行锁以及其他位于二者之间的间隙锁。 全局锁 锁定整个数据库&…...
树莓派A+安装lnmp-第一步,安装mariadb
20:26 2024/12/27 第一件事情,当然是超频!!! raspi-config 4 Performance Options,选择P1 Overclock,可配置超频 不要贪心,选择900就可以!!! rootpia4:~#…...
C++:单例模式
创建自己的对象,同时确保对象的唯一性。 单例类只能有一个实例☞静态成员static☞静态成员 必须类外初始化 单例类必须自己创建自己的唯一实例 单例类必须给所有其他对象提供这一实例 静态成员类内部可以访问 构造函数私有化☞构造函数私有外部不能创建&#x…...
【数据结构】数据结构整体大纲
数据结构用来干什么的?很简单,存数据用的。 (这篇文章仅介绍数据结构的大纲,详细讲解放在后面的每一个章节中,逐个击破) 那为什么不直接使用数组、集合来存储呢 ——> 如果有成千上亿条数据呢ÿ…...
网页数据的解析提取之Beautiful Soup
前面博客介绍了正则表达式的相关用法,只是一旦正则表达式写得有问题,得到的结果就可能不是我们想要的了。而且每一个网页都有一定的特殊结构和层级关系,很多节点都用id或 class 作区分所以借助它们的结构和属性来提取不也可以吗? 本篇博客我…...
Ai写作人工智能官网模板源码
Mortal是响应式的Tailwind CSS 模板,适用于AI写作和文案智能生成网站。 可用于撰写博客内容、数字广告文案、技术写作、SEO内容、登陆页面文案、社交媒体内容、电子邮件营销、网站文案等。使用世界上流行的响应式CSS框架Tailwind CSS、HTML5、CSS3 和 Javascript构…...
VSCode 插件开发实战(七):插件支持了哪些事件,以及如何利用和监听这些事件
前言 VSCode 作为现代开发者的首选编辑器之一,其核心优势在于其高度可扩展性。通过自定义插件,开发者可以根据自己的需求对编辑器进行功能扩展和优化。在这些插件开发过程中,事件处理和监听机制尤为重要,它们允许插件在特定事件发…...
现货量化合约跟单系统开发策略指南
随着加密货币市场的日益发展,量化交易和合约跟单已经成为了投资者在市场中获取稳定收益的重要手段。现货量化合约跟单系统作为一种自动化交易工具,可以帮助用户自动执行交易策略,同时也能跟随成功的交易者进行复制交易,从而降低投…...
Flink的Watermark水位线详解
一、Flink的时间语义 Flink有如下三种时间语义: Flink的三种时间语义-CSDN博客 在实际应用中,一般会采用事件时间语义。而正如前面所说的,事件时间语义需要等窗口的数据全部到齐了,才能进行窗口计算。那么,什么时候数…...