多线程同步:使用 std::mutex 和 std::unique_lock 保护共享资源

在当今的软件开发中,多线程编程是一项至关重要的技术,它允许程序同时执行多个任务,从而提高应用程序的效率和响应速度。然而,多线程环境也带来了数据安全和一致性的挑战。在多个线程需要访问和修改同一数据资源的情况下,如果没有适当的同步机制,就可能发生竞态条件,导致数据不一致或程序行为的不确定性。为了解决这些问题,锁的概念应运而生。

锁是一种用于管理对共享资源访问的同步机制,主要用于多线程环境中保护共享资源,防止多个线程同时访问同一资源通过锁定机制,可以确保在任意时刻,只有一个线程可以访问关键的代码区域,从而维护了数据的完整性和一致性。常见的锁机制包括互斥锁(mutex)、读写锁(允许多个读操作同时进行,但写操作是独占的)和递归锁等。

 

基本概念

  • std::thread: C++标准库中的线程类,用于创建和管理线程。
  • std::mutex: 用于保护共享数据,防止多个线程同时访问同一资源。
  • std::unique_lock: 是一个RAII(资源获取即初始化)风格的mutex管理工具。它可以在构造时自动锁定关联的mutex,并在析构时自动释放mutex。

例子

目标:创建两个线程,共同操作一个共享的计数器(int类型),每个线程增加10000次计数器,使用std::mutex来同步对计数器的访问。

不使用锁的情况示例代码

首先,让我们看看在不使用互斥锁的情况下,多线程访问共享资源可能导致的问题。

#include <iostream>
#include <thread>

// 共享资源
int counter = 0;

void incrementCounter() {
    for (int i = 0; i < 10000; ++i) {
        ++counter;  // 直接修改共享资源,没有锁的保护
    }
}

int main() {
    std::thread t1(incrementCounter);
    std::thread t2(incrementCounter);

    t1.join();
    t2.join();

    std::cout << "Final counter value without mutex: " << counter << std::endl;
    return 0;
}

可能的输出

Final counter value without mutex: 13542

在这个示例中,因为两个线程都在尝试修改同一个变量而没有同步措施,所以最终的counter值并不是预期的20000,而是一个随机的值,这是因为发生了竞态条件。

使用锁的情况示例代码

现在,我们使用std::mutexstd::unique_lock来同步对共享资源的访问。

#include <iostream>
#include <thread>
#include <mutex>

// 共享资源
int counter = 0;
std::mutex mtx;

void incrementCounter() {
    for (int i = 0; i < 10000; ++i) {
        std::unique_lock<std::mutex> lock(mtx);  // 使用unique_lock来锁定mtx
        ++counter;
    }
}

int main() {
    std::thread t1(incrementCounter);
    std::thread t2(incrementCounter);

    t1.join();
    t2.join();

    std::cout << "Final counter value with mutex: " << counter << std::endl;
    return 0;
}

结果

Final counter value with mutex: 20000

在这个版本的代码中,每次修改共享资源counter时都通过std::unique_lock来确保只有一个线程可以执行这一操作。结果显示,最终的counter值正是预期的20000,说明通过锁正确地管理了线程间的资源访问。

为何不涉及变量 i

关于循环变量 i,它是每个线程的局部变量,而不是共享资源。每个线程在调用 incrementCounter 函数时都会有自己的 i 副本。因此,不需要通过互斥锁来保护对 i 的访问,因为不存在多个线程同时访问或修改同一个 i 的问题。

在多线程环境中,通常只有对共享资源的访问和修改才需要同步机制(如互斥锁)。局部变量自然地由各自的线程独立管理,不会引起线程间的冲突。

总结

在C++多线程编程中,std::mutexstd::unique_lock是保护共享数据和避免竞态条件的重要工具。通过使用std::unique_lock,可以更安全和便捷地管理锁的获取和释放,从而简化代码并减少因错误管理锁而导致的问题。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32学习和实践笔记(14):按键控制实验

消除抖动有软件和硬件两种方法 软件方法就是在首次检测到低电平时加延时&#xff0c;通常延时5-10ms&#xff0c;让抖动先过去&#xff0c;然后再来检测是否仍为低电平&#xff0c;如果仍然是&#xff0c;说明确实按下。 硬件方法就是加RC滤波电路&#xff0c;硬件方法会增加…

亚马逊---设计弹性架构

一个好的架构师可以做到以下几点&#xff1a; 根据需求设计事件驱动型架构、微服务架构和/或多层架构 确定架构设计中使用的组件的扩展策略 根据要求确定实现松耦合所需的AWS服务 确定何时使用容器 确定何时使用无服务器技术和模式 根据要求推荐合适的计算、存储、联网和数据库…

HarmonyOS NEXT 网格元素交换案例

网格元素交换案例 介绍 直接进行交换和删除元素会给用户带来不好的体验效果&#xff0c;因此需要在此过程中注入一些特色的动画来提升体验效果&#xff0c;本案例通过Grid组件、attributeModifier、以 及animateTo函数实现了拖拽动画和删除动画。 效果图预览 使用说明&#…

【网络】Burpsuite学习笔记

文章目录 1.介绍1.1 正常客户端与服务端通信&BurpSuite代理后1.2 下载激活参考地址1.3 代理设置1.4 Proxy SwitchyOmega 使用1.4.1 新建情景模式1.4.2 设置代理1.4.2 应用选项 1.5 FoxyProxy 使用1.6 安装证书1.6.1 方式一1.6.2 方式二1.6.3 浏览器安装证书1.6.4 或者直接双…

基于改进遗传算法的配电网故障定位(matlab代码)

1 主要内容 该程序复现文章《基于改进遗传算法的配电网故障定位》&#xff0c;将改进的遗传算法应用于配电网故障定位中, 并引入分级处理思想, 利用配电网呈辐射状的特点, 首先把整个配电网划分为主干支路和若干独立区域, 再利用该算法分别对各独立区域进行故障定位, 然后进行…

独立开源版:零点城市社交电商v2.1.2.4

源码介绍 独立版&#xff1a;零点城市社交电商v2.1.2.4 新增首页新增多弹窗 注意&#xff1a;如果没有此完整程序勿下载 全开源解密版代码&#xff0c;后端完全开源&#xff0c;前端是VUE前端&#xff0c;可自行二开自己想要的功能。 独立版零点城市社交电商 小程序致力于…

tcp bbr pacing 的对与错

前面提到 pacing 替代 burst 是大势所趋&#xff0c;核心原因就是摩尔定律逐渐失效&#xff0c;主机带宽追平交换带宽&#xff0c;交换机不再能轻易吸收掉主机突发&#xff0c;且随着视频类流量激增&#xff0c;又不能以大 buffer 做带宽后备。因此&#xff0c;主机必须 pacing…

CentOS的简单介绍及常用命令

1、CentOS 的简单介绍&#xff1a; CentOS是Community Enterprise Operating System的缩写&#xff0c;也叫做社区企业操作系统。是企业Linux发行版领头羊Red Hat Enterprise Linux&#xff08;以下称之为RHEL&#xff09;的再编译版本&#xff08;是一个再发行版本&#xff09…

华为海思校园招聘-芯片-数字 IC 方向 题目分享——第五套

华为海思校园招聘-芯片-数字 IC 方向 题目分享——第五套 (共9套&#xff0c;有答案和解析&#xff0c;答案非官方&#xff0c;仅供参考&#xff09;&#xff08;共九套&#xff0c;每套四十个选择题&#xff09; 部分题目分享&#xff0c;完整版获取&#xff08;WX:didadida…

gazebo中vins-fusion在仿真小车上的部署

软件要求&#xff1a;Ubuntu 20.04 ros的noetic版本&#xff0c;我是在虚拟机vitrualbox上运行的 这几天在学ROS&#xff0c;跟着赵虚左老师过了一遍之后&#xff0c;感觉还是有很多不懂的地方&#xff0c;xtdrone上仿真跟着文档走了一遍&#xff0c;好像没学到什么东西&#…

【华为笔试题汇总】2024-04-17-华为春招笔试题-三语言题解(Python/Java/Cpp)

&#x1f36d; 大家好这里是KK爱Coding &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为近期的春秋招笔试题汇总&#xff5e; &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f…

【计算机考研】考408,还是不考408,性价比高❓

最近刷了很多帖子都偏向408太难了不要报考 但我的看法是408是计算机的考研趋势&#xff0c;并且择校的选择更多&#xff0c;408只是科目更广泛&#xff0c;与自命题相比其实各有各的难度 如果觉得自己数学基础不太好&#xff0c;时间不太够的同学可以了解一下自命题&#xff…

nodejs模块机制

模块机制 CommonJs规范 模块引用 上下文提供require()方法来引人外部模块var math require(math) 模块定义 exports 对象用于到处当前模块中的方法和变量module代表模块自身 exports.add function() {...}在另一个模块中使用require()方法进行导入。就可以使用 区别和联系 …

电力系统卫星授时信号安全隔离装置防护方案

电力系统是国家关键基础设施&#xff0c; 电力安全关系国计民生&#xff0c; 是国家安全的重要保障&#xff0c; 与政治安全、经济安全、 网络安全、社会安全等诸多领域密切关联。电网运行情况瞬息万变&#xff0c;为了在其发生事故时能够及时得到处理&#xff0c;需要统一的时…

Redis中的事务(二)

事务 一个完整的WATCH事务执行过程 假设当前服务端为c10086&#xff0c;而数据库watched_keys字典的当前状态如图所示&#xff0c;那么当c10086执行以下WATCH命令之后 c10086> WATCH "name" OKwatched_keys字典将更新如图所示的状态。接下来客户端c10086继续向…

[2021最新]Java时间戳和日期时间互转换

代码&#xff1a; import java.text.ParseException; import java.text.SimpleDateFormat;public class MainProcess {public static void main(String[] args) throws ParseException {// 1.set formatSimpleDateFormat timeSmat new SimpleDateFormat("yyyy-MM-dd HH:…

Kubernetes中安装部署ActiveMQ集群(手把手式记录)

目录 1、创建命名空间 nacos-cluster 2、配置文件准备 2.1 activemq0.xml 2.2 activemq1.xml 2.3 activemq2.xml 3、创建configMap cm-activemq 4、创建activemq-cluster.yaml 5、执行命令部署 6、部署成功&#xff0c;查看结果 这里以3个borker的集群为例&#xff0…

Facade 外观

意图 为子系统中的一组接口提供一个一致的界面&#xff0c;Facade模式定义了一个高层接口&#xff0c;这个接口使得这一字系统更加容易使用。 结构 其中&#xff1a; Facade知道哪些子系统负责处理请求&#xff1b;将客户的请求代理给适当的子系统对象。 Subsystem classes…

QGIS插件Geo-SAM使用(基于SAM半自动标注遥感图像)

0.Geo-SAM介绍 Geo-SAM是一个QGIS插件&#xff0c;旨在帮助人们在使用大尺寸地理空间栅格图像时有效地分割、描绘或标记地貌。Segment Anything Model &#xff08;SAM&#xff09; 是一个具有超能力的基础 AI 模型&#xff0c;但模型大小巨大&#xff0c;即使使用现代 GPU&am…

C++学习进阶版(一):用C++写简单的状态机实现

目录 一、基础知识 1、状态机 2、四大要素 3、描述方式 4、设计步骤 5、实现过程中需注意 &#xff08;1&#xff09; 状态定义 &#xff08;2&#xff09; 状态转换规则 &#xff08;3&#xff09; 输入处理 &#xff08;4&#xff09; 状态机的封装 &#xff08;5…