示例

仅供参考学习

#include <mutex>
#include <shared_mutex>
#include <thread>
#include <chrono>
#include <iostream>
#include <vector>// ============================================
// 1. std::mutex - 基本互斥锁
// ============================================
void basic_mutex_example() {std::mutex mtx;int counter = 0;// 1.1 使用 lock_guard - 最简单的RAII方式{std::lock_guard<std::mutex> lock(mtx);counter++;// 作用域结束时自动解锁}// 1.2 手动加锁解锁(不推荐,容易忘记解锁)mtx.lock();counter++;mtx.unlock();// 1.3 尝试加锁if (mtx.try_lock()) {counter++;mtx.unlock();}
}// ============================================
// 2. std::unique_lock - 灵活控制锁
// ============================================
void unique_lock_example() {std::mutex mtx;// 2.1 基本使用(类似lock_guard){std::unique_lock<std::mutex> lock(mtx);// 临界区代码} // 自动解锁// 2.2 延迟加锁{std::unique_lock<std::mutex> lock(mtx, std::defer_lock);// 此时还没有加锁// 做一些不需要锁的工作lock.lock();    // 手动加锁// 临界区工作lock.unlock();  // 手动解锁// 更多不需要锁的工作lock.lock();    // 再次加锁// 更多临界区工作} // 如果持有锁,会自动解锁// 2.3 尝试加锁{std::unique_lock<std::mutex> lock(mtx, std::try_to_lock);if (lock.owns_lock()) {// 成功获取锁std::cout << "获取锁成功\n";} else {std::cout << "获取锁失败\n";}}// 2.4 超时加锁(需要timed_mutex)std::timed_mutex timed_mtx;{std::unique_lock<std::timed_mutex> lock(timed_mtx, std::defer_lock);if (lock.try_lock_for(std::chrono::milliseconds(100))) {std::cout << "在100ms内获取锁成功\n";} else {std::cout << "超时,获取锁失败\n";}}// 2.5 移动语义auto create_lock = []() {std::unique_lock<std::mutex> lock(mtx);return lock;  // 可以移动返回};std::unique_lock<std::mutex> moved_lock = create_lock();// moved_lock现在持有锁
}// ============================================
// 3. std::shared_mutex - 读写锁
// ============================================
void shared_mutex_example() {std::shared_mutex rw_mtx;std::string shared_data = "初始数据";// 3.1 读锁 - 多个线程可以同时读auto reader = [&]() {std::shared_lock<std::shared_mutex> read_lock(rw_mtx);std::cout << "读取: " << shared_data << std::endl;// 可以有多个线程同时执行这里};// 3.2 写锁 - 独占访问auto writer = [&]() {std::unique_lock<std::shared_mutex> write_lock(rw_mtx);shared_data = "更新后的数据";std::cout << "写入完成" << std::endl;// 只有一个线程可以执行这里,且会阻塞所有读者};// 启动多个读线程和一个写线程std::vector<std::thread> threads;for (int i = 0; i < 3; ++i) {threads.emplace_back(reader);}threads.emplace_back(writer);for (auto& t : threads) {t.join();}
}// ============================================
// 4. std::recursive_mutex - 递归互斥锁
// ============================================
void recursive_mutex_example() {std::recursive_mutex rec_mtx;int count = 0;std::function<void(int)> recursive_func = [&](int n) {std::lock_guard<std::recursive_mutex> lock(rec_mtx);count++;std::cout << "递归层级: " << n << ", count: " << count << std::endl;if (n > 0) {recursive_func(n - 1);  // 同一线程可以多次获取锁}};recursive_func(3);
}// ============================================
// 5. std::timed_mutex - 超时互斥锁
// ============================================
void timed_mutex_example() {std::timed_mutex timed_mtx;// 5.1 尝试在指定时间内获取锁if (timed_mtx.try_lock_for(std::chrono::milliseconds(100))) {std::cout << "在100ms内获取锁成功\n";// 临界区工作timed_mtx.unlock();} else {std::cout << "超时,获取锁失败\n";}// 5.2 尝试在指定时间点前获取锁auto timeout_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(200);if (timed_mtx.try_lock_until(timeout_time)) {std::cout << "在指定时间点前获取锁成功\n";timed_mtx.unlock();} else {std::cout << "超时,获取锁失败\n";}
}// ============================================
// 6. 多锁管理 - 避免死锁
// ============================================
void multi_lock_example() {std::mutex mtx1, mtx2;// 6.1 std::lock - 同时锁定多个互斥锁,避免死锁{std::lock(mtx1, mtx2);  // 原子性地锁定两个互斥锁std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);// 临界区代码}// 6.2 std::scoped_lock (C++17) - 更简单的多锁管理{std::scoped_lock lock(mtx1, mtx2);  // 自动管理多个锁// 临界区代码}
}// ============================================
// 7. 条件变量配合使用
// ============================================
void condition_variable_example() {std::mutex mtx;std::condition_variable cv;bool ready = false;// 等待线程auto waiter = [&]() {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, [&] { return ready; });  // 等待条件满足std::cout << "条件满足,继续执行\n";};// 通知线程auto notifier = [&]() {std::this_thread::sleep_for(std::chrono::milliseconds(100));{std::lock_guard<std::mutex> lock(mtx);ready = true;}cv.notify_one();  // 通知等待的线程};std::thread t1(waiter);std::thread t2(notifier);t1.join();t2.join();
}// ============================================
// 8. 实际应用示例 - 线程安全的计数器
// ============================================
class ThreadSafeCounter {
private:mutable std::mutex mtx_;int count_ = 0;public:void increment() {std::lock_guard<std::mutex> lock(mtx_);++count_;}void decrement() {std::lock_guard<std::mutex> lock(mtx_);--count_;}int get() const {std::lock_guard<std::mutex> lock(mtx_);return count_;}// 复杂操作示例void add_if_positive(int value) {std::unique_lock<std::mutex> lock(mtx_);if (count_ > 0) {count_ += value;}}
};// ============================================
// 9. 性能考虑和最佳实践
// ============================================
void performance_tips() {std::mutex mtx;// ✅ 好的做法:尽量缩小临界区{int temp_result = 0;// 在锁外做复杂计算for (int i = 0; i < 1000; ++i) {temp_result += i * i;}std::lock_guard<std::mutex> lock(mtx);// 只在必要时持有锁// shared_data = temp_result;}// ❌ 不好的做法:在临界区内做复杂计算{std::lock_guard<std::mutex> lock(mtx);// 不要在锁内做复杂计算int result = 0;for (int i = 0; i < 1000; ++i) {result += i * i;}// shared_data = result;}
}int main() {std::cout << "=== C++ 互斥锁使用示例 ===" << std::endl;basic_mutex_example();unique_lock_example();shared_mutex_example();recursive_mutex_example();timed_mutex_example();multi_lock_example();condition_variable_example();// 测试线程安全计数器ThreadSafeCounter counter;std::vector<std::thread> threads;for (int i = 0; i < 10; ++i) {threads.emplace_back([&counter]() {for (int j = 0; j < 100; ++j) {counter.increment();}});}for (auto& t : threads) {t.join();}std::cout << "最终计数: " << counter.get() << std::endl;return 0;
}

核心概念总结
1. 互斥锁类型

  • std::mutex: 基本互斥锁,最常用
  • std::recursive_mutex: 递归锁,同一线程可多次获取
  • std::timed_mutex: 支持超时的互斥锁
  • std::shared_mutex: 读写锁,支持多读者单写者

2. 锁管理器

  • std::lock_guard: 最简单的RAII锁,构造时加锁,析构时解锁
  • std::unique_lock: 灵活的锁管理器,支持延迟加锁、手动控制等
  • std::shared_lock: 用于共享锁(读锁)
  • std::scoped_lock: C++17引入,用于管理多个锁

3. 锁标签

  • std::defer_lock: 延迟加锁
  • std::try_to_lock: 尝试加锁
  • std::adopt_lock: 接管已经持有的锁

4. 最佳实践

  1. 优先使用 lock_guard - 简单场景的首选
  2. 需要灵活控制时使用 unique_lock - 如需要手动解锁/加锁
  3. 读多写少用 shared_mutex - 提高并发性能
  4. 尽量缩小临界区 - 减少锁持有时间
  5. 避免死锁 - 使用 std::lock 或 std::scoped_lock 管理多个锁
  6. 配合条件变量使用 unique_lock - 因为条件变量需要能够释放锁

5. 选择建议

  • 简单保护:std::mutex + std::lock_guard
  • 需要灵活控制:std::mutex + std::unique_lock
  • 读多写少:std::shared_mutex + std::shared_lock/std::unique_lock
  • 递归调用:std::recursive_mutex
  • 超时需求:std::timed_mutex

这些工具组合使用可以解决绝大多数多线程同步问题。

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

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

相关文章

Android Handler机制与底层原理详解

Android 的 Handler 机制是跨线程通信和异步消息处理的核心框架&#xff0c;它构成了 Android 应用响应性和事件驱动模型的基础&#xff08;如 UI 更新、后台任务协调&#xff09;。其核心思想是 “消息队列 循环处理”。 核心组件及其关系Handler (处理器): 角色: 消息的发送…

jQuery JSONP:实现跨域数据交互的利器

jQuery JSONP&#xff1a;实现跨域数据交互的利器 引言 随着互联网的发展&#xff0c;跨域数据交互的需求日益增加。在Web开发中&#xff0c;由于同源策略的限制&#xff0c;直接通过XMLHttpRequest请求跨域数据会遇到诸多问题。而JSONP&#xff08;JSON with Padding&#xff…

Redis集群和 zookeeper 实现分布式锁的优势和劣势

在分布式系统中&#xff0c;实现分布式锁是确保多个节点间互斥访问共享资源的一种常见需求。Redis 集群 和 zookeeper 都可以用来实现这一功能&#xff0c;但它们有着各自不同的优势和劣势。 CAP 理论&#xff1a; 在设计一个分布式系统时&#xff0c;一致性&#xff08;Consis…

如何备份vivo手机中的联系人?

随着vivo移动设备在全球设立7个研发中心&#xff0c;vivo正在进入更多的国家。如今&#xff0c;越来越多的人开始使用vivo手机。以vivo X100为例&#xff0c;它配备了主摄像头和多个辅助摄像头&#xff0c;提供多样化的拍摄选项&#xff0c;并搭载了最新的FunTouch OS&#xff…

python脚本编程:使用BeautifulSoup爬虫库获取热门单机游戏排行榜

BeautifulSoup是一个便捷的解析html页面元素的python库&#xff0c;此处用来写一个简单的爬虫批量抓取国内游戏资讯网站的近期热门单机游戏排行榜。 网页来源如下所示代码 from bs4 import BeautifulSoup import requests# get web page web_url "https://www.3dmgame.co…

C#配置全面详解:从传统方式到现代配置系统

C#配置全面详解&#xff1a;从传统方式到现代配置系统 在软件开发中&#xff0c;配置是指应用程序运行时可调整的参数集合&#xff0c;如数据库连接字符串、API 地址、日志级别等。将这些参数从代码中分离出来&#xff0c;便于在不修改代码的情况下调整应用行为。C# 提供了多种…

数据中台架构解析:湖仓一体的实战设计

目录 一、数据中台与湖仓一体架构是什么 1. 数据中台 2. 湖仓一体架构 3. 湖仓一体在数据中台里的价值 二、湖仓一体架构的核心部件 1. 数据湖 2. 数据仓库 3. 数据集成工具 4. 数据分析与处理引擎 三、湖仓一体架构实战设计 1. 需求分析与规划 2. 数据湖建设 3. …

SQL Server表分区技术详解

表分区概述 表分区是将大型数据库表物理分割为多个较小单元的技术,逻辑上仍表现为单一实体。该技术通过水平分割数据显著提升查询性能,尤其针对TB级数据表可降低90%的响应时间。典型应用场景包含订单历史表、日志记录表等具有明显时间特征的业务数据,以及需要定期归档的审计…

WHIP(WebRTC HTTP Ingestion Protocol)详解

WHIP&#xff08;WebRTC HTTP Ingestion Protocol&#xff09;详解 WHIP&#xff08;WebRTC HTTP Ingestion Protocol&#xff09;是一种基于 HTTP 的协议&#xff0c;用于将 WebRTC 媒体流推送到媒体服务器&#xff08;如 SRS、Janus、LiveKit&#xff09;。它是为简化 WebRT…

图像噪点消除:用 OpenCV 实现多种滤波方法

在图像处理中&#xff0c;噪点是一个常见的问题。它可能是由于图像采集设备的缺陷、传输过程中的干扰&#xff0c;或者是光照条件不佳引起的。噪点会影响图像的质量和后续处理的效果&#xff0c;因此消除噪点是图像预处理的重要步骤之一。本文将介绍如何使用 OpenCV 实现几种常…

AI的Prompt提示词:英文写好还是中文好?

在与AI人大模型交互时,Prompt(提示词)的质量直接决定了输出的精准度和有效性。一个常见的问题是:究竟是用英文写Prompt好,还是用中文写更好?这并非一个简单的二元选择,而是涉及到语言模型的底层逻辑、表达的精确性以及个人使用习惯的综合考量。 英文Prompt的优势 模型训…

react的条件渲染【简约风5min】

const flag1true; console.log(flag1&&hello); console.log(flag1||hello); const flag20; console.log(flag2&&hello); console.log(flag2||hello); // &&运算符&#xff0c;如果第一个条件为假&#xff0c;则返回第一个条件&#xff0c;否则返回第二…

【RK3568+PG2L50H开发板实验例程】FPGA部分 | 紫光同创 IP core 的使用及添加

本原创文章由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注明出处&#xff08;www.meyesemi.com)1.实验简介实验目的&#xff1a;了解 PDS 软件如何安装 IP、使用 IP 以及查看 IP 手册实验环境&#xff1a;Window11 PD…

thinkphp微信小程序一键获取手机号登陆(解密数据)

微信小程序获取手机号登录的步骤相对较为简单,主要分为几个部分: 1.用户授权获取手机号: 微信小程序通过调用 wx.getPhoneNumber API 获取用户授权后,获取手机号。 2.前端获取用户的手机号: 用户在小程序中点击获取手机号时,系统会弹出授权框,用户同意后,你可以通过 …

数据库设计精要:完整性和范式理论

文章目录数据的完整性实体的完整性主键域完整性参照完整性外键多表设计/多表理论一对一和一对多多对多数据库的设计范式第一范式&#xff1a;原子性第二范式&#xff1a;唯一性第三范式&#xff1a;不冗余性数据的完整性 实体的完整性 加主键&#xff0c;保证一个表中每一条数…

智能推荐社交分享小程序(websocket即时通讯、协同过滤算法、时间衰减因子模型、热度得分算法)

&#x1f388;系统亮点&#xff1a;websocket即时通讯、协同过滤算法、时间衰减因子模型、热度得分算法&#xff1b;一.系统开发工具与环境搭建1.系统设计开发工具后端使用Java编程语言的Spring boot框架项目架构&#xff1a;B/S架构运行环境&#xff1a;win10/win11、jdk17小程…

部署NextCloud AIO + Frp + nginx-proxy-manager内网穿透私有云服务

网络拓扑 假设已有域名为nextcloud.yourhost.com 用户通过域名https访问 -> Nginx -> frps -> frpc -> NextCloud 其中Nginx和frps安装在具有公网IP的服务器上&#xff0c;frpc和NextCloud安装在内网服务器中。 Nginx配置 通过docker安装nginx-proxy-manager 外…

【源力觉醒 创作者计划】文心开源大模型ERNIE-4.5-0.3B-Paddle私有化部署保姆级教程及技术架构探索

一起来轻松玩转文心大模型吧&#x1f449;一文心大模型免费下载地址: https://ai.gitcode.com/theme/1939325484087291906 前言 2025年6月30日&#xff0c;百度正式开源文心大模型4.5系列&#xff08;ERNIE 4.5&#xff09;&#xff0c;涵盖10款不同参数规模的模型&#xff0…

大模型面试:如何解决幻觉问题

在大模型面试中回答“如何解决幻觉”问题时&#xff0c;需要展现你对问题本质的理解、技术方案的掌握以及工程实践的洞察。以下是一个结构化的回答框架和关键点&#xff0c;供你参考&#xff1a;回答框架&#xff1a;问题理解 -> 解决方案 -> 总结 1. 明确问题&#xff0…

matlab实现五自由度机械臂阻抗控制下的力跟踪

五自由度机械臂阻抗控制下的力跟踪,可以实现对力的跟踪反馈&#xff0c;基于MATLAB的机器人工具箱 eyebot.m , 767 zuakang_wailiraodong.m , 2568 colormp.mat , 682