C++中的条件变量(condition_variable)详解:小白版

生成带比例的小猫图片 (1).png

在编程中,我们经常需要处理多个任务,这些任务可能需要同时运行,也可能需要按照一定的顺序运行。这就涉及到了线程的概念。线程就像是一个小程序,它可以在程序中独立运行,而且可以和其他线程并行执行。

但是,有时候我们需要控制线程的执行顺序,比如有两个线程A和B,我们希望A执行完后,B才能开始执行。这就需要一种机制来同步线程的执行,这就是条件变量(std::condition_variable)的作用。

1. 什么是条件变量?

条件变量是一种特殊的变量,它可以让一个线程在某个条件成立之前等待,当条件成立时,这个线程就可以继续执行。条件变量通常和另一种叫做互斥锁(std::mutex)的东西一起使用,互斥锁可以保证在同一时间只有一个线程能访问某个资源。

2. 条件变量是如何工作的?

假设我们有两个线程A和B,我们希望A执行完后,B才能开始执行。我们可以这样做:

  1. 创建一个条件变量和一个互斥锁。
  2. 在A线程中,我们先锁定互斥锁,然后执行A线程的任务,任务完成后,我们解锁互斥锁,并通知条件变量。
  3. 在B线程中,我们也先锁定互斥锁,然后让B线程等待条件变量。当A线程通知条件变量后,B线程就会被唤醒,然后执行B线程的任务。

3. 条件变量的主要方法

条件变量有三个主要的方法:

  • wait:这个方法会让当前线程等待,直到条件变量被通知。
  • notify_one:这个方法会唤醒一个等待的线程。
  • notify_all:这个方法会唤醒所有等待的线程。

4. 条件变量的使用实例

让我们通过一个简单的实例来理解条件变量的使用。假设我们有两个线程,一个生产者线程和一个消费者线程。生产者线程负责生成数据,消费者线程负责处理数据。我们希望当生产者线程生成了数据后,消费者线程才开始处理数据。

首先,我们需要包含必要的头文件,并定义一些全局变量:

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>std::mutex mtx;
std::condition_variable cv;
bool ready = false;  // 用于表示数据是否已经生成

然后,我们定义生产者线程的函数:

void producer() {std::this_thread::sleep_for(std::chrono::seconds(2));  // 模拟数据生成过程std::lock_guard<std::mutex> lock(mtx);ready = true;  // 数据已经生成cv.notify_one();  // 通知消费者线程
}

接着,我们定义消费者线程的函数:

void consumer() {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, []{return ready;});  // 等待数据生成std::cout << "Consumer thread is processing data...\n";// 模拟数据处理过程std::this_thread::sleep_for(std::chrono::seconds(2));std::cout << "Data processed.\n";
}

最后,我们在主函数中启动这两个线程:

int main() {std::thread t1(producer);std::thread t2(consumer);t1.join();t2.join();return 0;
}

运行这个程序,你会看到消费者线程会等待生产者线程生成数据,当数据生成后,消费者线程才开始处理数据。

5. 生产者消费者问题的扩展

在上述的生产者消费者问题中,我们只有一个生产者和一个消费者。但在实际的应用中,我们可能会有多个生产者和消费者。此时,我们需要使用一个队列来存储数据,生产者将数据放入队列,消费者从队列中取出数据。

首先,我们需要定义一个队列和一些全局变量:

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>std::mutex mtx;
std::condition_variable cv;
std::queue<int> data_queue;  // 数据队列
bool finished = false;  // 用于表示生产者是否已经完成数据生成

然后,我们定义生产者线程的函数:

void producer(int id) {for (int i = 0; i < 5; ++i) {std::this_thread::sleep_for(std::chrono::seconds(1));  // 模拟数据生成过程std::lock_guard<std::mutex> lock(mtx);data_queue.push(i);std::cout << "Producer " << id << " produced data " << i << std::endl;cv.notify_one();  // 通知消费者线程}
}

接着,我们定义消费者线程的函数:

void consumer(int id) {while (true) {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, []{return !data_queue.empty() || finished;});  // 等待数据生成while (!data_queue.empty()) {int data = data_queue.front();data_queue.pop();std::cout << "Consumer " << id << " consumed data " << data << std::endl;// 模拟数据处理过程std::this_thread::sleep_for(std::chrono::seconds(1));}if (data_queue.empty() && finished) {break;}}
}

最后,我们在主函数中启动这些线程:

int main() {std::thread producers[2];std::thread consumers[2];for (int i = 0; i < 2; ++i) {producers[i] = std::thread(producer, i + 1);consumers[i] = std::thread(consumer, i + 1);}for (auto &p : producers) {p.join();}finished = true;cv.notify_all();for (auto &c : consumers) {c.join();}return 0;
}

在这个例子中,我们有两个生产者和两个消费者。生产者将数据放入队列,消费者从队列中取出数据。当所有的生产者都完成数据生成后,我们设置finishedtrue,并通知所有的消费者线程。

这就是如何使用条件变量来解决多生产者和多消费者的问题。通过使用条件变量,我们可以实现更复杂的线程同步需求。

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

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

相关文章

【python】OpenCV—Local Translation Warps

文章目录 1、功能描述2、原理分析3、代码实现4、效果展示5、完整代码6、参考 1、功能描述 利用液化效果实现瘦脸美颜 交互式的液化效果原理来自 Gustafsson A. Interactive image warping[D]. , 1993. 2、原理分析 上面描述很清晰了&#xff0c;鼠标初始在 C&#xff0c;也即…

STM32标准库学习笔记(十)SPI

前言 学习永无止境&#xff01;本篇是嵌入式开发之片上外设SPI&#xff0c;了解基本硬件原理以及通信协议。 注&#xff1a;本文章为学习笔记&#xff0c;部分图片与文字来源于网络/江协科技课程/手册&#xff0c;如侵权请联系&#xff01;谢谢&#xff01; 一、SPI通信概述 1.…

从github上,下载的android项目,从0-1进行编译运行-踩坑精力,如何进行部署

因为国内的网络原因&#xff0c;一直在anroidstudio开发的问题上&#xff0c;是个每个开发者都会踩坑 一直以为是自己的原因&#xff0c;其实很多都是国内网络的原因&#xff0c;今天就从一个开发者的视角 把从github上一个陌生的项目&#xff0c;如何通过本地就行运行的 首先…

计算机网络 (40)域名系统DNS

前言 计算机网络域名系统DNS&#xff08;Domain Name System&#xff09;是互联网的基础技术之一&#xff0c;它负责将人类可读的域名转换为计算机用来通信的数字IP地址。 一、基本概念 DNS的主要目的是将域名解析或翻译为IP地址&#xff0c;使得用户可以通过简单易记的域名来访…

使用Dify创建个问卷调查的工作流

为啥要使用Dify创建工作流呢&#xff1f;一个基于流程的智能体的实现&#xff0c;特别是基于业务的实现&#xff0c;使用Dify去实现时&#xff0c;通常都是一个对话工作流&#xff0c;当设计到相对复杂一些的流程时&#xff0c;如果将所有逻辑都放在对话工作流中去实现&#xf…

toRef 和 toRefs 详解及应用

在 Vue 3 中&#xff0c;toRef 和 toRefs 是两个用于创建响应式引用的工具&#xff0c;主要用于组合式 API&#xff08;Composition API&#xff09;的场景中 1. toRef 定义 toRef 将某个对象的某个属性包装成一个响应式引用。这样可以直接对该引用进行操作&#xff0c;而不需…

八 rk3568 android11 AP6256 蓝牙调试

一 经典蓝牙 经典蓝牙默认可以工作, 验证可以连接 蓝牙鼠标,键盘, 连接手机等等, 在 系统设置里打开蓝牙 ,扫描设备,配对连接即可。 注: 连接 ANDROID 手机的坑 1 手机连接之后空闲状态会断开 ,变成 配对的设备不是已连接,是正常,使用时又会自动 连接 2 手机传…

解读若依微服务架构图:架构总览、核心模块解析、消息与任务处理、数据存储与缓存、监控与日志

文章目录 1. 引言2. 架构总览3. 核心模块解析3.1 服务注册与配置中心Nacos&#xff1a;微服务的中枢 3.2 网关层ruoyi-gateway&#xff1a;服务的统一入口 3.3 核心业务服务3.4 认证服务ruoyi-auth&#xff1a;认证与授权的守护者 3.5 异构服务整合Sidecar&#xff1a;连接异构…

【MySQL】基础架构分析

考察频率难度40%⭐⭐⭐⭐ 这道题在面试时的出现频率其实并不高&#xff0c;最起码对于笔者来说是没有遇到过。那为什么还是选择把这个问题作为 MySQL 八股文系列的第一个呢&#xff1f;其实原因也挺简单的&#xff0c;还是老规矩&#xff0c;先通过一个问题把整个知识框架来一…

【已解决】【记录】2AI大模型web UI使用tips 本地

docker desktop使用 互动 如果需要发送网页链接&#xff0c;就在链接上加上【#】号 如果要上传文件就点击这个➕号 中文回复 命令它只用中文回复&#xff0c;在右上角打开【对话高级设置】 输入提示词&#xff08;提示词使用英文会更好&#xff09; Must reply to the us…

热烈祝贺“钛然科技”选择使用订单日记

感谢珠海钛然科技有限公司选择使用订单日记&#xff01; 珠海钛然科技有限公司&#xff0c;成立于2020年&#xff0c;位于广东省珠海市高新区&#xff0c;是一家以从事研发和生产功能型纳米高分子涂层为主的企业。 在业务不断壮大的过程中&#xff0c;想使用一种既能提升运营…

Linux-----进程通讯(消息队列)

目录 相关API 1.相关数据类型 mqd_t struct mq_attr struct timespec 2.相关系统调用接口 mq_open() mq_timedsend() && mq_send() mq_timedreceive() && mq_receive() mq_unlink() clock_gettime() 父子进程使用消息队列通讯 平行进程使用消息队列…

【微服务】面试题 5、分布式系统理论:CAP 与 BASE 详解

分布式系统理论&#xff1a;CAP 与 BASE 详解 一、CAP 定理 背景与定义&#xff1a;1998 年由加州大学科学家埃里克布鲁尔提出&#xff0c;分布式系统存在一致性&#xff08;Consistency&#xff09;、可用性&#xff08;Availability&#xff09;、分区容错性&#xff08;Part…

数据结构与算法之二叉树: LeetCode 572. 另一棵树的子树 (Ts版)

另一棵树的子树 https://leetcode.cn/problems/subtree-of-another-tree/description/ 描述 给你两棵二叉树 root 和 subRoot检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false二叉树 tree …

NineData云原生智能数据管理平台新功能发布|2024年12月版

本月发布 7 项更新&#xff0c;其中重点发布 2 项、功能优化 5 项。 重点发布 数据库 Devops - Oracle 非表对象支持可视化创建与管理 Oracle 非表对象&#xff0c;包括视图&#xff08;View&#xff09;、包&#xff08;Package&#xff09;、存储过程&#xff08;Procedur…

[Unity]MacOS下开发Unity

需要的插件 我使用的是vscode&#xff0c;经过长时间的使用我发现一个问题就是很多插件都是动态的在变化的&#xff0c;不是一成不变的&#xff0c;可能是重构&#xff0c;可能直接换了其他的工具。 所以这个插件也会是更新的状态。 2025年01月08日更新 .NET Install Tool (…

项目开发实践——基于SpringBoot+Vue3实现的在线考试系统(五)

文章目录 一、学生管理模块功能实现1、添加学生功能实现1.1 页面设计1.2 前端功能实现1.3 后端功能实现1.4 效果展示2、学生管理功能实现2.1 页面设计2.2 前端功能实现2.3 后端功能实现2.3.1 后端查询接口实现2.3.2 后端编辑接口实现2.3.3 后端删除接口实现2.4 效果展示二、代码…

实现一个VSCode插件(从创建到发布)

实现一个自己的VSCode 插件 本文将以 yo 为例&#xff0c; 实现一个 VS Code 插件 从创建到发布。 文章目录 实现一个自己的VSCode 插件1. 初始化项目2. 项目结构3. 实现插件功能4. 测试和运行插件5. 发布6. 下载自己发布的插件 1. 初始化项目 首先&#xff0c;我们需要安装 …

Unity TextMesh Pro入门

概述 TextMesh Pro是Unity提供的一组工具&#xff0c;用于创建2D和3D文本。与Unity的UI文本和Text Mesh系统相比&#xff0c;TextMesh Pro提供了更好的文本格式控制和布局管理功能。 本文介绍了TMP_Text组件和Tmp字体资产(如何创建字体资产和如何解决缺字问题),还有一些高级功…

【教程】数据可视化处理之2024年各省GDP排名预测!

过去的一年里&#xff0c;我国的综合实力显著提升&#xff0c;在新能源汽车、新一代战机、两栖攻击舰、航空航天、芯片电子、装备制造等领域位居全球前列。虽然全国各省市全年的经济数据公布还需要一段时间&#xff0c;但各地的工业发展数据&#xff0c;财政收入数据已大概揭晓…