【C++】互斥锁(Mutex)

在C++中,互斥锁(Mutex)是用于线程同步的重要工具,用于保护共享资源,防止多线程同时访问导致的数据竞争(Data Race)问题。
以下是C++中互斥锁的核心用法和示例:

一、基本互斥锁 std::mutex

1. 包含头文件
#include <mutex>
2. 保护共享资源
std::mutex mtx;  // 声明互斥锁
int shared_data = 0;  // 共享资源void increment() {mtx.lock();      // 加锁++shared_data;   // 临界区mtx.unlock();    // 解锁
}
3. 使用 std::lock_guard 自动管理锁
void safe_increment() {std::lock_guard<std::mutex> lock(mtx);  // 构造时加锁,析构时解锁++shared_data;                          // 自动保护临界区
}  // 离开作用域时锁自动释放

二、递归互斥锁 std::recursive_mutex

允许同一线程多次加锁,避免死锁:

std::recursive_mutex rmtx;void func1() {std::lock_guard<std::recursive_mutex> lock(rmtx);// 可以在此处再次加锁func2();
}void func2() {std::lock_guard<std::recursive_mutex> lock(rmtx);  // 同一线程可重入// ...
}

三、带超时的互斥锁 std::timed_mutex

std::timed_mutex tmtx;void try_lock_with_timeout() {// 尝试加锁,超时则放弃if (tmtx.try_lock_for(std::chrono::milliseconds(100))) {// 加锁成功tmtx.unlock();} else {// 加锁失败}
}

四、读写锁 std::shared_mutex(C++17)

允许多个线程同时读,但写时独占:

#include <shared_mutex>  // C++17std::shared_mutex rw_mutex;
std::string shared_data;// 读操作(共享锁)
void reader() {std::shared_lock<std::shared_mutex> lock(rw_mutex);// 允许多个读者同时访问std::cout << shared_data << std::endl;
}// 写操作(独占锁)
void writer() {std::unique_lock<std::shared_mutex> lock(rw_mutex);// 独占访问shared_data = "new data";
}

五、锁的高级用法

1. 避免死锁:使用 std::lock 同时锁多个互斥锁
std::mutex mtx1, mtx2;void safe_func() {// 原子性地锁多个互斥锁,避免死锁std::lock(mtx1, mtx2);std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);// ...
}
2. 延迟加锁 std::defer_lock
std::mutex mtx;void defer_lock_example() {std::unique_lock<std::mutex> lock(mtx, std::defer_lock);// 此时尚未加锁// ...lock.lock();  // 手动加锁// ...
}

六、常见错误与注意事项

  1. 忘记解锁
    使用 std::lock_guardstd::unique_lock 自动管理锁,避免手动 lock/unlock

  2. 锁粒度不当

    • 过大:性能下降(如锁整个函数)。
    • 过小:无法保护共享资源。
  3. 死锁风险

    • 避免嵌套锁。
    • 确保所有线程以相同顺序加锁。
  4. 性能考量

    • 读写锁(std::shared_mutex)适合读多写少的场景。
    • 无锁编程(Lock-Free)技术在高性能场景中更优。

七、示例:线程安全的计数器

#include <mutex>
#include <thread>
#include <iostream>class Counter {
private:int value = 0;std::mutex mtx;public:void increment() {std::lock_guard<std::mutex> lock(mtx);++value;}int get() {std::lock_guard<std::mutex> lock(mtx);return value;}
};int main() {Counter counter;std::thread t1([&]() {for (int i = 0; i < 10000; ++i) {counter.increment();}});std::thread t2([&]() {for (int i = 0; i < 10000; ++i) {counter.increment();}});t1.join();t2.join();std::cout << "Final value: " << counter.get() << std::endl;  // 输出:20000return 0;
}

八、C++ 互斥锁类型对比

类型特性适用场景
std::mutex基本互斥锁,不可重入简单互斥场景
std::recursive_mutex可重入锁,允许同一线程多次加锁递归函数或嵌套锁场景
std::timed_mutex支持超时的互斥锁需要尝试加锁并设置超时的场景
std::shared_mutex读写锁,允许多读一写读多写少的场景

合理选择互斥锁类型能有效提升代码的安全性和性能。

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

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

相关文章

Jsoup与HtmlUnit:两大Java爬虫工具对比解析

Jsoup&#xff1a;HTML解析利器 定位&#xff1a;专注HTML解析的轻量级库&#xff08;也就是快&#xff0c;但动态页面无法抓取&#xff09; 核心能力&#xff1a; DOM树解析与CSS选择器查询 HTML净化与格式化 支持元素遍历与属性提取 应用场景&#xff1a;静态页面数据抽…

小白成长之路-vim编辑

文章目录 Vim一、命令模式二、插入模式3.a:进入插入模式&#xff0c;在当前光标的后一个字符插入![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/fd293c3832ed49e2974abfbb63eeb5bb.png)4.o: 在当前光标的下一行插入5.i:在当前光标所在字符插入&#xff0c;返回命令模…

[redis进阶六]详解redis作为缓存分布式锁

目录 一 什么是缓存 缓存总结板书: 二 使⽤Redis作为缓存 三 缓存的更新策略 1) 定期⽣成 2) 实时⽣成 四 面试重点:缓存预热,缓存穿透,缓存雪崩 和缓存击穿 1)缓存预热 2)缓存穿透 3)缓存雪崩 4)缓存击穿 五 分布式锁 板书: 1)什么是分布式锁 2)分布式锁的基…

【MySQL】数据表插入数据

个人主页&#xff1a;Guiat 归属专栏&#xff1a;MySQL 文章目录 1. 插入数据概述1.1 插入数据的重要性1.2 插入数据的基本原则 2. 基本插入语句2.1 INSERT INTO语法2.2 插入多行数据2.3 不指定列名的插入2.4 插入NULL和默认值 3. 高级插入技术3.1 使用子查询插入数据3.2 IGNOR…

软考-软件设计师中级备考 14、刷题 算法

一、考点归纳 1&#xff09;排序 2、查找 3、复杂度 4、经典问题 0 - 1 背包动态规划0 - 1 背包问题具有最优子结构性质和重叠子问题性质。通过动态规划可以利用一个二维数组来记录子问题的解&#xff0c;避免重复计算&#xff0c;从而高效地求解出背包能装下的最大价值。分…

【阿里云】阿里云 Ubuntu 服务器无法更新 systemd(Operation not permitted)的解决方法

零、前言 目前正在使用的Ubuntu服务器中&#xff0c;仅阿里云&#xff08;不止一台&#xff09;出现了这个问题&#xff0c;因此我判定是阿里云服务器独有的问题。如果你的服务器提供商不是阿里云&#xff0c;那么这篇文章可能对你没有帮助。 如果已经因为升级错误导致依赖冲突…

css 点击后改变样式

背景&#xff1a; 期望实现效果&#xff1a;鼠标点击之后&#xff0c;保持选中样式。 实现思路&#xff1a;在css样式中&#xff0c;:active 是一种伪类&#xff0c;用于表示用户当前正在与被选定的元素进行交互。当用户点击或按住鼠标时&#xff0c;元素将被激活&#xff0c;此…

采用AI神经网络降噪算法的语言降噪消回音处理芯片NR2049-P

随着AI时代来临.通话设备的环境噪音抑制也进入AI降噪算法时代. AI神经网络降噪技术是一款革命性的语音处理技术&#xff0c;他突破了传统单麦克风和双麦克风降噪的局限性,利用采集的各种日常环境中的噪音样本进行训练学习.让降噪算法具有自适应噪声抑制功能&#xff0c;可以根…

不用联网不用编程,PLC通过智能网关快速实现HTTP协议JSON格式与MES等系统平台双向数据通讯

智能网关IGT-DSER集成了多种PLC的原厂协议&#xff0c;方便实现各种PLC、智能仪表通过HTTP协议与MES等各种系统平台通讯对接。PLC内不用编写程序&#xff0c;设备不用停机&#xff0c;通过网关的参数配置软件(下载地址)配置JSON文件的字段与PLC寄存器地址等参数即可。 …

如何将两台虚拟机进行搭桥

将两台虚拟机实现网络互通&#xff08;“搭桥”&#xff09;需配置虚拟网络&#xff0c;以下是基于 VMware Workstation 和 VirtualBox 的详细操作指南&#xff08;以 Windows 系统为例&#xff0c;Linux 原理类似&#xff09;&#xff1a; 一、VMware Workstation 配置&#x…

Xianyu AutoAgent,AI闲鱼客服机器人

Xianyu AutoAgent是一款专为闲鱼平台开发的智能客服机器人系统&#xff0c;旨在提供全天候的自动化服务。它具备多专家协同决策、智能议价和上下文感知对话等功能&#xff0c;能够管理轻量级的对话记忆&#xff0c;利用完整的对话历史为用户提供更自然的交流体验。 Xianyu Aut…

键盘输出希腊字符方法

在不同操作系统中&#xff0c;输出希腊字母的方法有所不同。以下是针对 Windows 和 macOS 系统的详细方法&#xff0c;以及一些通用技巧&#xff1a; 1.Windows 系统 1.1 使用字符映射表 字符映射表是一个内置工具&#xff0c;可以方便地找到并插入希腊字母。 • 步骤&#xf…

什么是SparkONYarn模式

1. 什么是 Spark on YARN&#xff1f; Spark on YARN 是 Apache Spark 的一种部署模式&#xff0c;允许 Spark 应用程序在 Hadoop YARN 集群上运行&#xff0c;充分利用 YARN 的资源管理和调度能力。这种模式将 Spark 与 Hadoop 生态深度集成&#xff0c;使企业能够在同一集群…

【git】clone项目后续,github clone的网络配置,大型项目git log 输出txt,切换commit学习,goland远程,自存档

git网络配置&#xff0c;解决git clone github速度奇慢 git config --global http.proxy http://127.0.0.1:7897 git config --global https.proxy http://127.0.0.1:7897git log输出到文件&#xff08;便于checkout&#xff09; 这里有些字符如表情会乱码&#xff0c;不知道…

Java游戏服务器开发流水账(3)游戏数据的缓存简介

简介 游戏服务器数据缓存是一种在游戏服务器运行过程中&#xff0c;用于临时存储经常访问的数据的技术手段&#xff0c;旨在提高游戏性能、降低数据库负载以及优化玩家体验。游戏开发中数据的缓存可以使用Java自身的内存也可以使用MemCache&#xff0c;Redis&#xff0c;注意M…

STL?vector!!!

一、前言 之前我们借助手撕string加深了类和对象相关知识&#xff0c;今天我们将一起手撕一个vector&#xff0c;继续深化类和对象、动态内存管理、模板的相关知识 二、vector相关的前置知识 1、什么是vector&#xff1f; vector是一个STL库中提供的类模板&#xff0c;它是存储…

C++学习之路,从0到精通的征途:继承

目录 一.继承的概念及定义 1.继承的概念 2.继承的定义 (1)继承的定义格式 (2)继承基类成员访问方式的变化 二.基类与派生类间的转换 1.派生类对象赋值给基类的引用/指针 2. 派生类对象直接赋值给基类对象 三.继承的作用域 四.派生类的默认成员函数 1.构造函数 2.拷…

用vue和go实现登录加密

前端使用CryptoJS默认加密方法&#xff1a; var pass CryptoJS.AES.encrypt(formData.password, key.value).toString()使用 CryptoJS.AES.encrypt() 时不指定加密模式和参数时&#xff0c;CryptoJS 默认会执行以下操作 var encrypted CryptoJS.AES.encrypt("明文&quo…

React百日学习计划——Deepseek版

阶段一&#xff1a;基础巩固&#xff08;1-20天&#xff09; 目标&#xff1a;掌握HTML/CSS/JavaScript核心语法和开发环境搭建。 每日学习内容&#xff1a; HTML/CSS&#xff08;1-10天&#xff09; 标签语义化、盒模型、Flex布局、Grid布局、响应式设计&#xff08;媒体查询…

WPF中如何自定义控件

WPF自定义控件简化版&#xff1a;账户菜单按钮&#xff08;AccountButton&#xff09; 我们以**“账户菜单按钮”为例&#xff0c;用更清晰的架构实现一个支持标题显示、渐变背景、选中状态高亮**的自定义控件。以下是分步拆解&#xff1a; 一、控件核心功能 我们要做一个类似…