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

C++并发编程:构建线程安全队列(第一部分:粗粒度锁)

C++并发编程:构建线程安全队列(第一部分:粗粒度锁)

引言

在多线程编程中,线程之间的数据共享和通信是一个非常重要的问题。在这篇博客中,我们将讨论如何用C++实现一个基础但非常实用的线程安全队列。这个队列使用粗粒度的互斥锁和条件变量来实现。

线程安全队列的基础实现

下面是基础代码结构:

template <typename T>
class threadsafe_queue
{
private:mutable std::mutex mut;std::queue<std::shared_ptr<T>> data_queue;std::condition_variable data_cond;// ...(省略其余代码)
};

互斥锁和条件变量

  • std::mutex mut: 用于确保队列操作的线程安全。
  • std::condition_variable data_cond: 用于阻塞和唤醒等待队列操作的线程。

push方法

void push(T new_value)
{std::shared_ptr<T> data(std::make_shared<T>(std::move(new_value)));std::unique_lock lk(mut);data_queue.push(data);data_cond.notify_one();
}

这里使用 std::unique_lock 来获取互斥锁,确保数据的线程安全。然后使用 data_cond.notify_one() 来唤醒可能正在等待队列变为非空的线程。

pop方法

对于 pop,我们有两个版本:

  1. wait_and_pop:等待直到队列非空。
  2. try_pop:尝试弹出,如果队列为空则立即返回。
void wait_and_pop(T& value)
{std::unique_lock lk(mut);data_cond.wait(lk, [this] { return !data_queue.empty(); });value = std::move(*data_queue.front());data_queue.pop();
}bool try_pop(T& value)
{std::unique_lock lk(mut);if (data_queue.empty()) return false;value = std::move(*data_queue.front());data_queue.pop();return true;
}

wait_and_pop 中,我们使用 data_cond.wait() 来阻塞当前线程,直到队列变为非空。

测试

我们使用了一个生产者线程和两个消费者线程进行测试。

// 测试函数
void test_threadsafe_queue()
{threadsafe_queue<int> tsq;// 创建一个生产者线程std::thread producer([&](){for (int i = 0; i < 10; ++i){std::cout << "Pushing " << i << std::endl;tsq.push(i);}});// 创建两个消费者线程std::thread consumer1([&](){for (int i = 0; i < 5; ++i){int value;tsq.wait_and_pop(value);std::cout << "Consumer 1 popped " << value << std::endl;}});std::thread consumer2([&](){for (int i = 0; i < 5; ++i){int value;tsq.wait_and_pop(value);std::cout << "Consumer 2 popped " << value << std::endl;}});// 等待所有线程完成producer.join();consumer1.join();consumer2.join();
}

完整代码

template <typename T>
class threadsafe_queue
{
private:mutable std::mutex mut;std::queue<std::shared_ptr<T>> data_queue;std::condition_variable data_cond;public:threadsafe_queue() = default;void wait_and_pop(T& value){std::unique_lock lk(mut);data_cond.wait(lk, [this] { return !data_queue.empty(); });value = std::move(*data_queue.front());data_queue.pop();}bool try_pop(T& value){std::unique_lock lk(mut);if (data_queue.empty()) return false;value = std::move(*data_queue.front());data_queue.pop();return true;}std::shared_ptr<T> wait_and_pop(){std::unique_lock lk(mut);data_cond.wait(lk, [this] { return !data_queue.empty(); });std::shared_ptr<T> res = data_queue.front();data_queue.pop();return res;}std::shared_ptr<T> try_pop(){std::unique_lock lk(mut);if (data_queue.empty()) return std::make_shared<T>();std::shared_ptr<T> res = data_queue.front();data_queue.pop();return res;}void push(T new_value){std::shared_ptr<T> data(std::make_shared<T>(std::move(new_value)));std::unique_lock lk(mut);data_queue.push(data);data_cond.notify_one();}bool empty(){std::unique_lock lk(mut);return data_queue.empty();}
};// 测试函数
void test_threadsafe_queue()
{threadsafe_queue<int> tsq;// 创建一个生产者线程std::thread producer([&](){for (int i = 0; i < 10; ++i){std::cout << "Pushing " << i << std::endl;tsq.push(i);}});// 创建两个消费者线程std::thread consumer1([&](){for (int i = 0; i < 5; ++i){int value;tsq.wait_and_pop(value);std::cout << "Consumer 1 popped " << value << std::endl;}});std::thread consumer2([&](){for (int i = 0; i < 5; ++i){int value;tsq.wait_and_pop(value);std::cout << "Consumer 2 popped " << value << std::endl;}});// 等待所有线程完成producer.join();consumer1.join();consumer2.join();
}int main()
{test_threadsafe_queue();return 0;
}

总结

这篇博客中,我们简要介绍了如何使用C++的标准库来实现一个基础的线程安全队列。虽然我们使用了粗粒度的互斥锁,但这个实现是非常实用和直观的。在下一篇博客中,我们将讨论如何进行优化,以提高性能和效率。

相关文章:

C++并发编程:构建线程安全队列(第一部分:粗粒度锁)

C并发编程&#xff1a;构建线程安全队列&#xff08;第一部分&#xff1a;粗粒度锁&#xff09; 引言 在多线程编程中&#xff0c;线程之间的数据共享和通信是一个非常重要的问题。在这篇博客中&#xff0c;我们将讨论如何用C实现一个基础但非常实用的线程安全队列。这个队列…...

C++设计模式-更新中

单例模式 这个类实现了单例模式。单例模式是一种设计模式&#xff0c;旨在确保一个类只有一个实例&#xff0c;并提供一个全局访问点来获取该实例。 在 ConnectionManager 类中&#xff0c;它通过以下方式实现了单例模式&#xff1a; 构造函数 ConnectionManager() 被声明为…...

Hydra工具的使用

目录 Hydra初识 Hydra使用 hydra破解mysql 前言 不固定用户名密码爆破 hydra破解ssh 以用户名为密码登录 hydra破解rdp 将爆破密码的结果输出到文件中 Hydra初识 前言&#xff1a; hydra是一款开源的暴力破解工具&#xff0c;支持多种服务破解原理&#xff1a;使用户…...

Pytorch学习:卷积神经网络—nn.Conv2d、nn.MaxPool2d、nn.ReLU、nn.Linear和nn.Dropout

文章目录 1. torch.nn.Conv2d2. torch.nn.MaxPool2d3. torch.nn.ReLU4. torch.nn.Linear5. torch.nn.Dropout 卷积神经网络详解&#xff1a;csdn链接 其中包括对卷积操作中卷积核的计算、填充、步幅以及最大值池化的操作。 1. torch.nn.Conv2d 对由多个输入平面组成的输入信号…...

水果库存系统(SSM+Thymeleaf版)

不为失败找理由&#xff0c;只为成功找方法。所有的不甘&#xff0c;因为还心存梦想&#xff0c;所以在你放弃之前&#xff0c;好好拼一把&#xff0c;只怕心老&#xff0c;不怕路长。 文章目录 一、前言二、系统架构与需求分析1、技术栈1.1 后端1.2 前端 2、需求分析 三、设计…...

如何在VueJS应用程序中设置Toast通知

通知是开发者提升应用程序互动性和改善用户体验的强大工具。通过利用通知&#xff0c;开发者可以在用户与应用程序互动的同时&#xff0c;有效地向用户传达重要事件。 通知在应用程序中起着至关重要的作用&#xff0c;可以及时通知用户有关各种操作和事件的信息。它们可以用于通…...

css让元素保持等比例宽高

使用新属性 aspect-ratio: 16/9; 代码示例 <style>div {width: 60%;/* 等比例宽高 */aspect-ratio: 16/9;background-color: red;margin: auto;}</style> </head><body><div></div> </body>示例 aspect-ratio兼容性...

骨传导和入耳式哪个危害大一点?入耳式和骨传导哪种好?

骨传导和入耳式这两种耳机虽然都存在一定的危害&#xff0c;但是入耳式耳机对人体的危害要更大一点。 入耳式耳机直接塞进耳朵这种佩戴方式&#xff0c;会阻塞外部声音的进入&#xff0c;长时间使用可能会导致耳道感染&#xff0c;还可能对听力造成损伤&#xff0c;而骨传导耳…...

介绍OpenCV

OpenCV是一个开源计算机视觉库&#xff0c;可用于各种任务&#xff0c;如物体识别、人脸识别、运动跟踪、图像处理和视频处理等。它最初由英特尔公司开发&#xff0c;目前由跨学科开发人员社区维护和支持。OpenCV可以在多个平台上运行&#xff0c;包括Windows、Linux、Android和…...

Android中的view绘制流程,简单理解

简单理解 Android中的View类代表用户界面中基本的构建块。一个View在屏幕中占据一个矩形区域、并且负责绘制和事件处理。View是所有widgets的基础类&#xff0c;widgets是我们通常用于创建和用户交互的组件&#xff0c;比如按钮、文本输入框等等。子类ViewGroup是所有布局&…...

商城开发:店铺管理系统应具备哪些功能?

电子商务的迅猛发展&#xff0c;越来越多的企业选择在线商城作为业务拓展的重要渠道。而要实现一个成功的在线商城&#xff0c;一个强大而高效的店铺管理系统是不可或缺的。店铺管理系统作为商城的核心管理工具&#xff0c;应具备一系列功能&#xff0c;以提供卓越的用户体验和…...

小白学go基础04-命名惯例对标识符进行命名

计算机科学中只有两件难事&#xff1a;缓存失效和命名。 命名是编程语言的要求&#xff0c;但是好的命名却是为了提高程序的可读性和可维护性。好的命名是什么样子的呢&#xff1f;Go语言的贡献者和布道师Dave Cheney给出了一个说法&#xff1a;“一个好笑话&#xff0c;如果你…...

使用iCloud和Shortcuts实现跨设备同步与自动化数据采集

在如今的数字时代&#xff0c;跨设备同步和自动化数据采集对于提高工作效率和便利性至关重要。苹果的iCloud和Shortcuts App为我们提供了强大的工具&#xff0c;可以实现跨设备同步和自动化数据采集的功能。本文将详细介绍如何利用iCloud和Shortcuts App实现这些功能&#xff0…...

Spring框架-基于STOMP使用Websocket

文章目录 前言一、范例演示1.注解方式2.XML方式二、可能出现错误错误: WebSocket代理中断错误: 缺少EventExecutor类错误: 缺少Publisher类错误: 缺少Scheduler类错误: WebSocket调用失败总结前言 Spring框架提供了多种WebSock消息机制,不仅包含了模拟SockJS,还提供了基…...

kafka-- 安装kafka manager及简单使用

一 、安装kafka manager 管控台&#xff1a; # 安装kafka manager 管控台&#xff1a; ## 上传 cd /usr/local/software ## 解压 unzip kafka-manager-2.0.0.2.zip -d /usr/local/ cd /usr/local/kafka-manager-2.0.0.2/conf vim /usr/local/kafka-manager-2.0.0.2/conf/appl…...

深圳-海岸城购物中心数据分析

做数据分析的时候&#xff0c;如果要对商场进行分析&#xff0c;可以从这些数据纬度进行分析&#xff0c;如下图所示&#xff1a; 截图来源于数位观察&#xff1a;https://www.swguancha.com/...

vue3 + elementplus Cannot read properties of null (reading ‘isCE‘)

使用命令行直接下载的element-plus&#xff0c;使用时会报错。 卸载掉&#xff0c;然后在项目根目录下&#xff0c;使用vue ui安装依赖&#xff0c; 即可使用...

易云维®医院后勤管理系统软件利用物联网智能网关帮助实现医院设备实现智能化、信息化管理

近年来&#xff0c;我国医院逐渐意识到医院设备信息化管理的重要性&#xff0c;逐步建立医院后勤管理系统软件&#xff0c;以提高信息化管理水平。该系统是利用数据库技术&#xff0c;为医院的中央空调、洁净空调、电梯、锅炉、医疗设备等建立电子档案&#xff0c;把设备监控、…...

c# 定期重启程序操作

1 先说说重启//这部分是转载的 一、Restart方法 System.Windows.Forms.Application.Restart();经测试发现有时候只会关闭程序&#xff0c;并不会重新启动 二、Process.Start()和Exit() System.Diagnostics.Process.Start(System.Reflection.Assembly.GetExecutingAssembly()…...

ps beta 2.5的妙用

1、https://pan.baidu.com/s/1CCw6RGlzEJ7TPWou8pPADQ?pwd2023 2、下载新便携版。 3、解压到c:\myapp文件夹下。 4、运行。 5、登录us账号。 6、使用智能移除。 效果如下&#xff1a; 使用滤镜。 先将C:\myApp\&#xff08;新便携版&#xff09;Adobe Photoshop (25.0.0 m22…...

【雷达成像】主动式毫米波安检成像【含Matlab源码 15238期】

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;Matlab武动乾坤博客之家&#x1f49e;…...

如何通过Odoo合同自动化与电子签名实现企业文档管理数字化转型

如何通过Odoo合同自动化与电子签名实现企业文档管理数字化转型 【免费下载链接】odoo Odoo. Open Source Apps To Grow Your Business. 项目地址: https://gitcode.com/GitHub_Trending/od/odoo 企业在合同管理过程中常面临效率低下、合规风险高、协作成本大等挑战。传统…...

Youtu-VL-4B-Instruct基础教程:system message规范写法避免API响应异常

Youtu-VL-4B-Instruct基础教程&#xff1a;system message规范写法避免API响应异常 你是不是在用Youtu-VL-4B-Instruct的API时&#xff0c;偶尔会遇到一些奇怪的响应&#xff1f;比如模型突然不按套路出牌&#xff0c;或者干脆给你返回一些看不懂的内容&#xff1f; 别担心&a…...

当I2C总线卡死时我们在debug什么:从复位异常到多设备冲突的故障树分析

当I2C总线卡死时我们在debug什么&#xff1a;从复位异常到多设备冲突的故障树分析 I2C总线作为嵌入式系统中广泛使用的通信协议&#xff0c;其简洁的两线制设计&#xff08;SCL时钟线与SDA数据线&#xff09;背后隐藏着复杂的硬件交互逻辑。当系统突然出现I2C通信失败、设备无响…...

RTKLIB进阶指南:深入理解北斗三代CNAV电文与BDS-3星历数据结构

RTKLIB进阶指南&#xff1a;北斗三代CNAV电文与星历数据结构深度解析 当你在RTKLIB的源码中第一次看到eph_t结构体里那些神秘的Adot、ndot字段时&#xff0c;是否好奇过它们如何精确描述北斗三号卫星的轨道变化&#xff1f;这些看似简单的浮点数背后&#xff0c;隐藏着中国自主…...

Wan2.2-I2V-A14B在微信小程序开发中的应用:实时图片转视频功能实现

Wan2.2-I2V-A14B在微信小程序开发中的应用&#xff1a;实时图片转视频功能实现 1. 引言 "一张照片能变成视频吗&#xff1f;"这是很多社交类小程序用户常有的疑问。想象一下&#xff0c;用户在电商小程序上传商品图片后&#xff0c;系统自动生成一段展示视频&#…...

3步实现UMA模型吸附能预测:从数据准备到结果验证完整指南

3步实现UMA模型吸附能预测&#xff1a;从数据准备到结果验证完整指南 【免费下载链接】ocp Open Catalyst Projects library of machine learning methods for catalysis 项目地址: https://gitcode.com/GitHub_Trending/oc/ocp 在催化材料研究中&#xff0c;吸附能是评…...

别再只用DataParallel了!PyTorch单机多卡训练保姆级教程(从DP到DDP实战避坑)

从DataParallel到DDP&#xff1a;PyTorch单机多卡训练深度优化指南 当你的模型参数突破1亿大关&#xff0c;单卡训练时间从几小时延长到几天时&#xff0c;多GPU并行训练就从一个可选项变成了必选项。但面对PyTorch提供的DataParallel(DP)和DistributedDataParallel(DDP)两种方…...

SDMatte新手入门:交互式点选,让复杂抠图变简单

SDMatte新手入门&#xff1a;交互式点选&#xff0c;让复杂抠图变简单 1. 什么是SDMatte&#xff1f; SDMatte是一款基于扩散模型的交互式图像抠图工具&#xff0c;由vivoCameraResearch团队开发。它通过简单的点选操作&#xff0c;就能实现专业级的图像抠图效果&#xff0c;…...

Ostrakon-VL-8B与传统算法对比展示:在复杂背景下的菜品分割

Ostrakon-VL-8B与传统算法对比展示&#xff1a;在复杂背景下的菜品分割 不知道你有没有遇到过这样的烦恼&#xff1a;想给美食拍张照&#xff0c;结果背景里堆满了杂乱的餐具、餐巾纸&#xff0c;甚至还有手机和钥匙&#xff0c;想单独把菜品抠出来&#xff0c;用传统的修图工…...