C++并发编程之玩转condition_variable

news2025/1/31 8:00:59

C++并发编程之玩转condition_variable

0.导语

最近在看并发编程相关的代码,自己顺手从0开始写了个小项目玩转并发场景下的生产消费者模型,如果你想提高多线程编程方面的能力,想熟练掌握condition_variable的使用,甚至想在面试当中凸显这一块的技术时,不妨与我一起探讨本篇文章。

本篇文章将会从会引入以下几个版本:

1.CPU轮询等待版单生产者单消费者:

该版本使用了简单的轮询机制,生产者不断地检查消费者是否已经消费完数据。这种模式简单直接,但效率较低,因为生产者在没有数据时仍然在忙等待。

2.等待通知版单生产者单消费者:

该版本引入了等待通知机制,生产者在没有数据时会等待消费者的通知。这种模式避免了忙等待,提高了效率,同时减少了资源消耗。

3.等待通知版单生产者多消费者:

在这个版本中,引入了多个消费者,它们共享生产者的数据。生产者在产生数据后,通知所有消费者进行处理。

4.等待通知版多生产者多消费者:

这个版本支持多个生产者和多个消费者,生产者之间和消费者之间共享数据。生产者在产生数据后,通知所有消费者进行处理。

5.单生产者多消费者并行版:

在这个版本中,引入了并行处理机制,多个消费者可以同时处理数据。生产者产生数据后,多个消费者并行处理,提高了整体处理速度。

6.多生产者多消费者并行版:

这个版本支持多个生产者和多个消费者,并且允许并行处理。多个生产者并行产生数据,多个消费者并行处理数据,提高了整体并发能力。

7.支持Lambda回调的优雅停止版:

在这个版本中,引入了Lambda回调函数,用于优雅地停止并发处理。可以通过调用回调函数来停止生产者和消费者的处理,并进行清理工作

通过这几个版本的学习可以掌握:

1.多线程和并发编程:通过这些版本的描述,您可以了解到如何在C++中使用多线程和并发编程来处理并行任务。您将学习如何创建线程、控制线程的执行、线程间的数据共享和同步等。

2.同步机制:在这些版本中,介绍了不同的同步机制,如轮询等待、等待通知和回调函数。您将学习如何使用互斥锁、条件变量、信号量等来实现线程间的同步和协调。

3.Lambda表达式:在支持Lambda回调的版本中,您将学习如何使用C++11引入的Lambda表达式来编写简洁而灵活的回调函数,以实现优雅的停止机制。

4.代码组织和构建工具:提到了支持bazel编译的能力,这可以让您学习如何使用构建工具来组织和管理复杂的C++项目。

5.condition_variable、mutex、unique_lock

这次写的小项目非常硬核源码已同步放在星球,感兴趣的扫码加入,下面来简单聊聊每个细节。

0b009c1bf024805acf1031426f6ab4b3.jpeg

1. CPU轮训等待版单生产者单消费者

这个版本效率非常低,而低效率来自于繁忙等待循环,因为CPU停留在循环中什么都不做。忙碌等待并不是最佳策略。根本原因是,除了轮询,我们没有办法让一个线程知道另一个线程已经完成。我们需要一个线程更直接的方式来通知其他线程。条件变量是为这些场景创建的。

for (;;) {
    std::unique_lock<std::mutex> ul(mutex_);
    data_ = rand() % 100;
    std::cout << "produce data: " << data_ << std::endl;
    ready_ = true;
    ul.unlock();
    while (ready_) {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

2.等待通知版单生产者单消费者

在这个版本我们借助condition_variable,完成多线程之间的同步操作。

std::condition_variable cv_;
bool ready_{false};

生产者会不断生成一个随机数并将其存储在 data_ 变量中,然后将 ready_ 标志设置为 true,表示有可用的数据。接着,它通知等待的消费者线程,然后自己等待消费者线程处理完数据。

cv_.wait(ul, [this]() { return !ready_; });

消费者将会在一个无限循环中等待生产者通知数据的可用性。当 ready_ 标志为 true 时,它会从 data_ 变量中获取数据并进行处理,然后将 ready_ 标志设置为 false,表示数据已经被消费。接着,它通知生产者线程,然后自己等待生产者线程生成新的数据。

cv_.wait(ul, [this]() { return ready_; });

3.等待通知版单生产者多消费者

前面的版本中,我们还是单生产,单个消费者,如何做到多个消费者抢占消费?

此时需要引入队列,我们将任务丢到队列中去,随后多个消费者进行消费即可,与上述等待条件不同点在于队列的状态。

对于生产者:如果队列大小未达到 max_queue_size_ 的限制,如果队列已满,则生产者线程将等待消费者线程从队列中取走一些数据。

cv_.wait(ul, [this]() { return queue_.size() < max_queue_size_; });

对于消费者:队列有数据就消费,否则等待。

cv_.wait(ul, [this]() { return !queue_.empty(); });

4.等待通知版多生产者多消费者

对于这个版本比较简单,基于第三个版本继续优化,创建n个生产者线程即可。

5.单生产者多消费者并行版

对于以上版本有个比较大的问题,当生产者生产的数据到达上限时,消费者此时在消费,而生产者并没有动起来,它在等待消费者消费完才能进行,如何让生产者与消费者同时运转呢?

改进点在于使用多个cv,来回切换通知。

std::condition_variable cv_producer_;
std::condition_variable cv_consumer_;

6.多生产者多消费者并行版

基于5进行改造,支持多个生产者即可。

7.支持Lambda回调的优雅停止版

在上面版本中,我们的程序是一直生产、一直消费,如何优雅停止住?

这个停止条件能够让用户去控制,例如:我想写一个lambda回调函数,是否可以支持呢?

答案是可以的,例如:

w.SetStopConditionCallback([&]() {
  return w.GetProducedCount() >= threshold;
});

这个例子为:当生产者生产的数量到达一定阈值时,程序结束。

因此,我们便可以写出这样的代码。

if (stop_condition_callback_() && queue_.empty()) {
   break;
}

以上便是本次小项目的一些点,比较有意思,也非常的实用,在面试与实际学习的过程中会学到不少东西,欢迎大家与我一起探讨并发编程~

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Go 语言精进之路——Go 中常见并发模式总结

文章目录 前言创建模式退出模式分离模式join 模式notify-and-wait模式退出模式的应用 管道模式扇出与扇入模式 超时与取消模式 前言 在语言层面&#xff0c;Go针对CSP模型提供了三种并发原语。 goroutine&#xff1a;对应CSP模型中的P&#xff0c;封装了数据的处理逻辑&#x…

数字化赋能大健康实体行业迈入发展新阶段,大健康招商加盟系统优势有哪些?

数字经济的发展&#xff0c;正推动大健康实体行业迈入高质量发展新阶段。大健康实体行业应如何在数字化浪潮中抢占先机&#xff1f;大健康实体行业招商加盟平台应如何开发设计&#xff0c;才能帮助大健康企业主取得营收突破&#xff1f; 围绕蚓链大健康招商加盟系统&#xff0c…

ppt制作相关内容小结

ppt制作是天大的事&#xff01;是讲清一件事&#xff0c;表达自己的最好方式 1.删除ppt中的所有备注信息2.ppt制作中的快捷键3.精美的ppt收集 这里还是要提醒自己一下&#xff0c;做好ppt是外在的事情&#xff0c;把道理吃透才是根本&#xff01; 但是ppt外在也是表达的一种方式…

闭包实现函数柯里化,js实现

闭包实现函数柯里化&#xff0c;js实现 函数柯里化定义代码实现 函数柯里化定义 柯里化&#xff08;Currying&#xff09;是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数&#xff0c;并且返回接受余下的参数且返回结果的新函数的技术 即函数可以接…

.NET 8 Preview 4 中的 ASP.NET Core 更新

作者&#xff1a;Daniel Roth - Principal Program Manager, ASP.NET 翻译&#xff1a;Alan Wang 排版&#xff1a;Alan Wang .NET 8 Preview 4 现已可用&#xff0c;并包括了许多对 ASP.NET Core 的新改进。 以下是本预览版本中的新内容摘要&#xff1a; Blazor 使用 Blazor …

图片:前端展示图像(img 、picture、svg、canvas )及常用图片格式(PNG、JPG、JPEG、WebP、GIF、SVG、AVIF等)

一、浏览器网页展示图片方法 1.1、HTML <img> 标签 <!DOCTYPE html> <html><head><title>图片展示</title></head><body><h1>图片展示</h1><img src"example.jpg" alt"Example Image" w…

项目——学生信息管理系统3

目录 班级添加的界面实现 创建班级的实体类 在org.xingyun.dao 包下 编写 ClassDao 创建 AddStudentClassFrm 添加班级页面 注意创建成 JInternalFrame 类型 给控件起个名字 注释掉main方法 给提交按钮绑定事件 回到 MainFrm.java 给添加班级按钮绑定事件 启动测试 班…

chatgpt赋能python:Python重写父类的方法

Python重写父类的方法 在Python中&#xff0c;继承是一个常见的概念。通过继承&#xff0c;子类可以使用父类中定义的属性和方法。有时候&#xff0c;子类需要改变父类中的行为。这时候&#xff0c;可以通过重写父类的方法来实现这一目的。 什么是重写方法&#xff1f; 当一…

区块链生态发展

文章目录 前言以太坊的到来什么是图灵完备&#xff1f;什么是智能合约&#xff1f; 以太坊的应用去中心化应用 DApp代币发行 公有链&联盟链区块链应用总结 前言 前面的区块链文章有介绍区块链的诞生以及底层运行原理&#xff0c; 本文主要介绍一下区块链应用的发展&#x…

(八)灌溉系统-将nodejs部署到云服务器(未实现,思路供参考)

这里之后我就是升级优化了 如果不想再学习的话&#xff0c;前面的就足够用了 Node后端部署上线详细步骤及踩坑记录&#xff08;使用宝塔面板&#xff09;&#xff1a;参考文章 Xshelll7下载&#xff1a;教程 这里是成功连上了

如何使用 Terraform 和 Git 分支有效管理多环境?

作者&#xff5c;Sumeet Ninawe 翻译&#xff5c;Seal软件 链接&#xff5c;https://spacelift.io/blog/terraform-environments 通常我们使用 Terraform 将我们的基础设施定义为代码&#xff0c;然后用 Terraform CLI 在我们选择的云平台中创建制定的基础设施组件。从表面上看…

C++primer(第五版)第五章(语句)

5.1简单语句 一个语句在末尾加上分号;就变成了表达式语句.表达式语句的作用是执行表达式并丢弃掉求值结果(也可以用赋值运算符将求值结果存起来),不存起来的话,大多数表达式语句是没有什么实际用处的表达式语句,例如: int a10; a5; //这就是没什么用的表达式语句 ; …

《Linux操作系统编程》第四章 屏幕编程器vi : 了解屏幕编辑器vi的概述和基本操作命令

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

基于单片机自动控制的电动模型汽车

摘 要 本文研究了一种基于单片机自动控制的电动模型汽车。主要论述了自动循迹、避障、测距跟随等自动驾驶相关技术在模型车上的应用。 模型汽车以STM32为主控芯片&#xff0c;采用了多种传感器、驱动电机、控制舵机等检测与控制模块&#xff0c;实现了路径循迹行驶和检测避障的…

【python】numpy的array数组与pandas的DataFrame表格互相转换(图文代码超详细)

目录 0.环境 1.array数组和DataFrame表格的简单介绍 2.转换方式详解&#xff08;代码&#xff09; 0&#xff09;前提&#xff1a;【需注意】 1&#xff09;array转化为DataFrame 2&#xff09;DataFrame转化为array 3&#xff09;完整代码 0.环境 windows jupyter note…

英语统考错题集_作文题---网络教育统考工作笔记003

scholar 学者 下面是关于统考中的作文的如何书写,要打个照面,不能到时候蒙了 sincere 真诚的 cover 覆盖 excited 激动的 兴奋的 sincerely 真诚的 absent 缺勤的 citizen 公民 居民 每种题型都接触一下,然后后面有时间继续扩充中.. 152下上

ansible 变量与事实变量

Ansible变量与事实变量&#xff1a; 自定义变量&#xff1a; 变量可以在定义任务前进行定义&#xff0c;也可以从其他文件中调用。 下面我写了一个在任务前定义的变量&#xff0c;并用循环将其打印。 内部变量&#xff1a; 剧本如下&#xff1a; --- - hosts: localhostva…

基于51单片机开发的步进电机远程控制系统

摘 要 电机是日常生活中必不可少的一部分&#xff0c;同时也是一种常用的机电元件。步进电机是一种特殊的电机&#xff0c;相较于其他类型的电机&#xff0c;步进电机的优点更加突出、应用优势更加明显&#xff0c;广泛应用于各个领域。 本设计是基于单片机开发的步进电机远程…

力扣算法刷题Day47|休息日总结:动态规划之背包问题

背包问题 〉题型分类 解题套路 〉动规五部曲 确定dp数组&#xff08;dp table&#xff09;以及下标的含义确定递推公式dp数组如何初始化确定遍历顺序举例推导dp数组 解题技巧 〉递推公式 问背包装满后的最大价值&#xff1a;dp[j] max(dp[j], dp[j - weight[i]] value[i]) …

JMeter之简单控制线程组(Thread Group)组件的执行顺序

jmeter的线程类型一共有3种分别是setUp线程组、tearDown线程组和线程组 他们的执行优先级为 setUp线程组 > 线程组(Thread Group) > tearDown线程组 当存在多个线程组(Thread Group)&#xff0c;jmeter默认是同时执行的&#xff0c;也就是说是无序的&#xff0c;此时如果…