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

C++并发之探索编程三

文章目录

  • 1. 等待事件或等待其他条件
    • 1.1 凭借条件变量等待条件成立
      • 1.1.1 std::condition_variable
      • 1.1.2 std::condition_variable_any
      • 1.1.3 std::condition_variable和std::condition_variable_any之间的区别

  1. 上个章节我们讨论了如何对共享数据的一个保护,通过std::lock_guard、std::unique_lock、初始化过程中使用std::call_once、std::once_flag、多个线程读取少量线程写入的时候使用std::shared_lock、std::unique_lock和std::shared_mutex或std::shared_timed_mutex搭配使用,还有单线程递归加锁的方式std::recursive_mutex的使用方法。
  2. 但是有时候我们不仅需要保护共享数据,还需要令独立线程上的行为同步。那么本章节我们就来讲一下线程同步的几种方法。

1. 等待事件或等待其他条件

有的时候需要各个线程之间协同操作,比如A线程需要等待B线程完成某一个功能之后才开始执行,那么有没有什么办法,B线程完成功能之后通知A线程一声,然后A线程接受到信号之后就开始工作呢?肯定是有的。

1.1 凭借条件变量等待条件成立

那么就开始介绍std::condition_variable 和 std::condition_variable_any的使用。
std::condition_variable 和 std::condition_variable_any 是 C++ 中用于多线程同步的两个类。它们都允许线程在等待某个条件变为真之前挂起自己,以免造成无谓的 CPU 时间浪费。

1.1.1 std::condition_variable

std::condition_variable 是 C++11 中引入的一个线程同步原语,用于在等待某个条件变为真之前挂起当前线程。使用 std::condition_variable 时,通常需要先定义一个 std::mutex,因为std::condition_variable仅限于与std::mutex一起使用,然后用 std::unique_lockstd::mutex 对其进行上锁,最后通过 std::condition_variable::wait() 解锁并且挂起当前线程:

#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;void worker_thread() {// 等待条件变为真std::unique_lock<std::mutex> lck(mtx);while (!ready) {cv.wait(lck);}// 条件已经变为真,执行一些操作// ...if (lck.owns_lock()){std::cout << "lck has locked" << std::endl;}
}int main() {// 模拟某些操作std::this_thread::sleep_for(std::chrono::seconds(5));// 通知等待的线程条件已经变为真{std::lock_guard<std::mutex> lck(mtx);ready = true;}cv.notify_one();std::thread t(worker_thread);t.join();return 0;
}

在上面的代码中,worker_thread() 函数等待 ready 变为 true,如果当前 ready 的值为 false,则调用 cv.wait(lck) 挂起当前线程,同时释放 lck。当 cv.notify_one() 被调用时,cv.wait(lck) 会返回,worker_thread() 函数会重新获得 lck,然后执行一些操作。

需要注意的是,由于 std::condition_variable::wait() 可能会出现虚假唤醒(即没有被 notify 也会从 wait() 函数中返回),因此在使用 std::condition_variable 时,通常需要将等待条件的语句用循环包围起来,以确保条件变为真时不会错过信号。
当然也可以这样写:

#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;void worker_thread() {// 等待条件变为真std::unique_lock<std::mutex> lck(mtx);cv.wait(lck, [&]() {return ready; }); // 条件已经变为真,执行一些操作// ...if (lck.owns_lock()){std::cout << "lck has locked" << std::endl;}
}int main() {// 模拟某些操作std::this_thread::sleep_for(std::chrono::seconds(5));// 通知等待的线程条件已经变为真{std::lock_guard<std::mutex> lck(mtx);ready = true;}cv.notify_one();std::thread t(worker_thread);t.join();return 0;
}

在段代码里面使用了cv.wait(lock, [&]() { return ready; })进行等待条件成立。正好在此介绍一下std::condition_variable::wait()函数的用法:

std::condition_variable::wait()是一个用于等待通知的函数,其使用方式如下:

template< class Predicate > 
void wait(std::unique_lock<std::mutex>& lock, Predicate pred ); 

其中,lock是一个已经加锁的互斥量(必须是 std::unique_lock 类型),pred是一个可调用对象,用于判断等待条件是否满足。函数执行时会自动释放锁,并阻塞当前线程直到被通知。当线程被通知后,函数会重新获得锁,并重新检查等待条件。如果等待条件满足,函数返回;否则,函数再次进入阻塞状态等待下一次通知。

1.1.2 std::condition_variable_any

std::condition_variable_any 是 C++11 中引入的另一个线程同步原语,它的作用与 std::condition_variable 相同,但是可以与任何可锁定的互斥量(std::mutex、std::shared_mutex、std::recursive_mutex)等等一起使用。使用 std::condition_variable_any 时,需要先定义一个互斥量,然后使用 std::unique_lock 对其进行上锁。

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>std::mutex mtx;
std::condition_variable_any cv;
bool ready = false;void worker_thread() {// 等待条件变为真{std::unique_lock<std::mutex> lck(mtx);while (!ready) {cv.wait(lck);}}// 条件已经变为真,执行一些操作// ...std::cout << "shared data" << std::endl;
}int main() {// 模拟某些操作std::this_thread::sleep_for(std::chrono::seconds(1));// 通知等待的线程条件已经变为真{std::lock_guard<std::mutex> lck(mtx);ready = true;}cv.notify_one();std::thread t(worker_thread);t.join();return 0;
}

注意:至于为什么能在main函数中使用std::lock_guard,而在worker_thread()函数中不能使用std::lock_guard,这是因为std::condition_variable或者std::condition_variable_any在等待操作的过程中要释放互斥量,如果使用 std::lock_guard,那么在等待操作期间就无法释放互斥量,从而无法满足 std::condition_variable 的要求。

std::unique_lock 比 std::lock_guard 更灵活,因为它允许在构造时不锁定互斥量,在析构时再解锁。这使得 std::unique_lock 可以用于实现一些更为复杂的同步操作,例如超时等待、可重入锁等。此外,std::unique_lock 还提供了一些额外的功能,例如手动锁定和解锁互斥量、转移互斥量的所有权等。

在使用 std::condition_variable或者std::condition_variable_any时,我们通常需要使用 std::unique_lock 来锁定互斥量,并在等待操作期间释放互斥量。这样可以让其他线程获得互斥量并修改共享变量,从而避免死锁的情况。

1.1.3 std::condition_variable和std::condition_variable_any之间的区别

std::condition_variable 和 std::condition_variable_any 都是用于多线程同步的 C++ 标准库类,它们的主要区别在于:

  • 适用范围:
    std::condition_variable 只能与 std::unique_lockstd::mutex 配合使用,而 std::condition_variable_any 可以与任何能够提供 lock() 和 unlock() 成员函数的互斥量配合使用,包括 std::mutex、std::recursive_mutex、std::shared_mutex 等等。
  • 实现细节:
    std::condition_variable_any 的实现可能比 std::condition_variable 更为复杂,因为它需要支持不同类型的互斥量,而且可能需要在等待队列中存储更多的信息来避免死锁和无效的等待。

综上所述,std::condition_variable 更为简单且更为常用,适用于绝大多数的同步场景。而 std::condition_variable_any 则更加灵活,适用于一些特殊的同步场景,例如需要使用不同类型的互斥量、需要跨线程进行等待和通知等。

相关文章:

C++并发之探索编程三

文章目录1. 等待事件或等待其他条件1.1 凭借条件变量等待条件成立1.1.1 std::condition_variable1.1.2 std::condition_variable_any1.1.3 std::condition_variable和std::condition_variable_any之间的区别上个章节我们讨论了如何对共享数据的一个保护&#xff0c;通过std::lo…...

某智能驾驶企业:CACTER云网关为O365系统护航

01 客户背景 某智能驾驶企业是一家国际性的高科技创新型企业&#xff0c;在智能驾驶领域处于全球领先地位&#xff0c;专注于为广大客户提供个性化的智能驾驶解决方案&#xff0c;共建美好智能新时代。 使用产品&#xff1a;CACTER邮件安全云网关 02 痛点难点问题 根据Corema…...

网络安全与信息安全的主要区别讲解-行云管家

生活中工作中&#xff0c;我们经常可以听到信息安全与网络安全这两个词语&#xff0c;但很多小伙伴对于两者区分不清楚&#xff0c;今天我们小编就给大家来简单讲解一下这两者的主要区别吧&#xff01; 网络安全与信息安全的主要区别讲解 1、定义不同 网络安全是指网络系统的…...

Zabbix6.2利用模板和自定义监控项监控华为AR3260路由器

1&#xff1a;登录路由器的WEB管理控制台。在系统管理中找到SNMP然后开启SNMP代理&#xff0c;SNMP的版本可以只选择v2c都选择也无所谓&#xff0c;然后点击新建一个团体。 2&#xff1a;团体名称输入默认的public即可&#xff0c;在WEB端显示的是乱码&#xff0c;但是不影响使…...

MySQL Connector/C++使用过程中的问题

Linux环境下&#xff0c;使用mysql connector cpp的时候&#xff0c;链接的时候报错&#xff1a; /usr/bin/ld: warning: libssl.so.10, needed by /usr/lib64/libssh2.so.1, may conflict with libssl.so.1.1 /usr/bin/ld: ext/openssl/.libs/xp_ssl.o: undefined reference …...

SpringBoot下的Spring——DAY04——动态代理总结、AOP、自定义注解进行拦截、动态获取注解参数、通知方法(内含源代码)

SpringBoot下的Spring——DAY04——动态代理总结、AOP、自定义注解进行拦截、动态获取注解参数、通知方法&#xff08;内含源代码&#xff09; 源代码下载链接地址&#xff1a;https://download.csdn.net/download/weixin_46411355/87549575 目录SpringBoot下的Spring——DAY0…...

Spark MLlib概述

Spark MLlib概述机器学习房价预测模型选型数据探索数据提取准备训练样本模型训练模型效果评估机器学习 机器学习的过程 : 基于历史数据&#xff0c;机器会根据一定的算法&#xff0c;尝试从历史数据中挖掘并捕捉出一般规律再把找到的规律应用到新产生的数据中&#xff0c;从而…...

Git 命令行5步解决冲突方法(亲测有效)

总体步骤如下&#xff1a; git pull --rebase 解决冲突文件 file1.c。git add file1.cgit commit -m "*****" git pushgit rebase --continue &#xff0c;此时冲突消失强推&#xff0c;git push origin xxxx -f 本人解决的例子如下&#xff1a; 第一步、拉取…...

在线帮助文档——让用户更方便地获取帮助

在当今互联网时代&#xff0c;人们在使用各种产品或服务时&#xff0c;难免会遇到问题或疑问&#xff0c;需要寻求帮助。而在线帮助文档则成为了一种方便、快捷、高效的解决问题的方式。Baklib作为一款优雅的云知识库构建平台&#xff0c;可以帮助公司在线制作各种类型的帮助文…...

一小时轻松掌握Git,看这一篇就足够

文章目录序言&#xff1a;版本控制分类一、Git环境配置下载卸载安装二、常用linux命令三、基本配置四、Git基本操作0.原理图1.项目创建及克隆方式一&#xff1a;本地仓库搭建方式二&#xff1a;克隆远程仓库2.文件操作3.配置ssh公钥4.分支5.push代码参考序言&#xff1a;版本控…...

spring cloud stream 自定义binder

背景xxx,关键字 binder stream &#xff0c;解决多中间件通信及切换问题直接主菜&#xff1a;spring cloud stream 架构中间件 --- binder --- channel --- sink --- &#xff08;处理&#xff09;---source ---channel ---binder ---中间件 springcloudstream已自己集成了kafk…...

计算机网络之HTTP协议

目录 一、HTTP的含义 1.1 理解超文本 1.2 理解应用层协议 1.3 理解HTTP协议的工作过程 二、HTTP协议格式 2.1 抓包工具的使用 2.2 理解协议格式 2.2.1 请求协议格式 2.2.2. 响应格式请求 一、HTTP的含义 HTTP&#xff08;全称为“超文本传输协议”&#xff09;&#x…...

如何挖掘专利创新点?

“无意中发现了一个巨牛的人工智能教程&#xff0c;忍不住分享一下给大家。教程不仅是零基础&#xff0c;通俗易懂&#xff0c;而且非常风趣幽默&#xff0c;像看小说一样&#xff01;觉得太牛了&#xff0c;所以分享给大家。点这里可以跳转到教程。” 对于广大的软件工程师来说…...

虚函数和纯虚函数

多态&#xff08;polymorphism&#xff09;是面向对象编程语言的一大特点&#xff0c;而虚函数是实现多态的机制。其核心理念就是通过基类访问派生类定义的函数。多态性使得程序调用的函数是在运行时动态确定的&#xff0c;而不是在编译时静态确定的。使用一个基类类型的指针或…...

Framework源码面试——Handler与事件传递机制面试集合

Handler面试题 Handler的作用&#xff1a; 当我们需要在子线程处理耗时的操作&#xff08;例如访问网络&#xff0c;数据库的操作&#xff09;&#xff0c;而当耗时的操作完成后&#xff0c;需要更新UI&#xff0c;这就需要使用Handler来处理&#xff0c;因为子线程不能做更新…...

iOS开发-bugly符号表自动上传发布自动化shell

这里介绍的是通过build得到的app文件和dSYM文件来打包分发和符号表上传。 通过Archive方式打包和获得符号表的方式以后再说。 一&#xff1a;bugly工具jar包准备 bugly符号表工具下载地址&#xff1a;(下载完成后放入项目目录下&#xff0c;如不想加入git可通过gitIgnore忽略…...

MySQL OCP888题解046-哪些语句会被记录到binlog

文章目录1、原题1.1、英文原题1.2、中文翻译1.3、答案2、题目解析2.1、题干解析2.2、选项解析3、知识点3.1、知识点1&#xff1a;binlog_format选项3.2、知识点2&#xff1a;Performance Schema(性能模式)4、总结1、原题 1.1、英文原题 You enable binary logging on MySQL S…...

【前端学习】D5:CSS进阶

文章目录前言系列文章目录1 精灵图Sprites1.1 为什么需要精灵图&#xff1f;1.2 精灵图的使用2 字体图标iconfont2.1 字体图标的产生2.2 字体图标的优点2.3 字体文件格式2.4 字体图标的使用2.5 字体图标的引入2.6 字体图标的追加3 CSS三角3.1 普通三角3.2 案例4 CSS用户界面样式…...

【bioinfo】融合检测软件FusionMap分析流程和报告结果

文章目录写在前面FusionMap融合检测原理FusionMap与其他软比较FusionMap分析流程FusionMap结果文件说明FusionMap mono CUP设置图片来源: https://en.wikipedia.org/wiki/Fusion_gene写在前面 下面主要内容是关于RNA-seq数据分析融合&#xff0c;用到软件是FusionMap 【Fusion…...

C++基础了解-17-C++日期 时间

C日期 & 时间 一、C日期 & 时间 C 标准库没有提供所谓的日期类型。C 继承了 C 语言用于日期和时间操作的结构和函数。为了使用日期和时间相关的函数和结构&#xff0c;需要在 C 程序中引用 头文件。 有四个与时间相关的类型&#xff1a;clock_t、time_t、size_t 和 …...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...