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

std::mutex

std::mutex是 C++ 标准库(自 C++11 起引入)中用于多线程编程的核心组件,位于<mutex>头文件中。它代表互斥量(Mutual Exclusion),用于保护共享数据,防止多个线程同时访问导致的数据竞争(Data Race)。

以下是关于std::mutex的核心用法、最佳实践及注意事项:

1. 基本用法

std::mutex提供了两个主要成员函数:

  • lock(): 尝试获取锁。如果锁已被其他线程持有,当前线程会阻塞直到锁被释放。
  • unlock(): 释放锁。

原始用法示例(不推荐直接使用,见下文“最佳实践”):

#include <iostream> #include <thread> #include <mutex> std::mutex mtx; int shared_data = 0; void increment() { mtx.lock(); // 加锁 ++shared_data; mtx.unlock(); // 解锁 } int main() { std::thread t1(increment); std::thread t2(increment); t1.join(); t2.join(); std::cout << "Result: " << shared_data << std::endl; return 0; }

2. 最佳实践:使用 RAII 锁守卫

手动调用lock()unlock()容易出错(例如在锁持有期间发生异常导致unlock()未被调用,造成死锁)。强烈建议使用 RAII(资源获取即初始化)机制的锁守卫类:

std::lock_guard(C++11)

最简单的锁守卫。构造时加锁,析构时自动解锁。适用于整个作用域都需要锁的情况。

#include <mutex> std::mutex mtx; void safe_increment() { std::lock_guard<std::mutex> lock(mtx); // 构造时加锁 // 临界区代码 // 函数退出(无论正常返回还是抛出异常)时,lock 析构,自动解锁 }
std::unique_lock(C++11)

lock_guard更灵活。支持延迟锁定、手动解锁、尝试锁定以及配合条件变量 (std::condition_variable) 使用。

#include <mutex> std::mutex mtx; void flexible_increment() { std::unique_lock<std::mutex> lock(mtx); // ... 做一些不需要锁的操作 ... lock.unlock(); // 可以手动提前解锁 // ... 做一些不需要锁的操作 ... lock.lock(); // 也可以重新加锁 }

3. 重要特性与限制

  • 不可复制/移动:std::mutex对象本身不能被复制或移动。这意味着包含std::mutex的类也不能默认生成拷贝构造函数或拷贝赋值运算符。
  • 非递归性:std::mutex非递归的。如果一个已经持有该锁的线程再次尝试lock()同一个 mutex,会导致死锁(Deadlock)。
    • 解决方案: 如果需要递归锁,请使用std::recursive_mutex
  • 所有权:std::mutex不记录拥有者线程 ID。虽然通常由加锁的线程解锁,但标准并未强制检查(不过在不同线程间传递锁通常逻辑上是错误的)。

4. 常见变体

类型描述适用场景
std::mutex标准互斥量,独占访问。绝大多数临界区保护。
std::recursive_mutex可递归互斥量。同一线程可多次加锁。必须在同一线程内递归调用受保护函数时(尽量避免设计成这样)。
std::timed_mutex带超时的互斥量。支持try_lock_fortry_lock_until需要避免无限等待,尝试获取锁失败后执行其他逻辑时。
std::recursive_timed_mutex可递归且带超时的互斥量。上述两者的结合。
std::shared_mutex(C++17)共享互斥量(读写锁)。允许多个读者或一个写者。读多写少的场景,提高并发读取性能。

5. 典型错误示例

死锁示例(自锁):

void bad_function(std::mutex& m) { std::lock_guard<std::mutex> lock1(m); // 以下代码会导致死锁,因为当前线程已经持有了 m std::lock_guard<std::mutex> lock2(m); }

异常安全示例(展示为什么需要 lock_guard):

void risky_function(std::mutex& m) { m.lock(); if (some_condition) { throw std::runtime_error("Error!"); // 如果没有 lock_guard,m.unlock() 永远不会被执行,锁泄露 } m.unlock(); }

使用std::lock_guard则无需担心此问题。

总结

在现代 C++ 开发中:

  1. 始终包含<mutex>
  2. 优先使用std::lock_guard管理std::mutex
  3. 仅在需要配合条件变量或需要精细控制锁生命周期时使用std::unique_lock
  4. 尽量避免手动调用lock()unlock()
http://www.cnnetsun.cn/news/1477692.html

相关文章:

  • 3个理由告诉你,为什么小熊猫Dev-C++是C/C++学习的最佳起点
  • 穿墙透视的WiFi革命:RuView无摄像头人体感知技术全解析
  • 边缘设备跑大模型?DeepSeek-R1-Distill-Qwen-1.5B实时推理实战
  • Linux系统AMD ROCm深度学习环境部署指南
  • 实战指南:基于虫洞ESP32S3-EYE开发板打造即插即用UVC免驱摄像头
  • BiLSTM在时间序列预测中的实战应用与优化策略
  • 告别剧本创作烦恼:Trelby开源效率工具让创作回归本质
  • Oracle 19c EM Express保姆级配置指南:从端口设置到防火墙放行,一次搞定
  • 这份榜单够用!高效论文写作全流程AI论文平台推荐(2026 最新)
  • 5分钟快速上手:Blender插件与资源终极指南,让你成为3D创作高手
  • AutoGLM-Phone-9B部署避坑指南:新手必看,确保一次成功
  • 如何免费创建个人数字分身?Duix.Avatar开源AI数字人工具完整指南
  • 终极AMD处理器调试指南:5个关键技巧释放硬件隐藏性能
  • 别再到处找了!微信小程序同声传译插件个人也能用,保姆级接入教程
  • S2-Pro模型部署精讲:CentOS 7系统下的Docker环境配置
  • C#_绘制竖向TabPages,TabControls
  • Seurat与Matrix包版本冲突?手把手教你解决CsparseMatrix_validate报错(R 4.2.2实测)
  • 云原生推理服务:KServe生产级部署全指南
  • 探索AI绘图新境界:Awesome Claude Skills创意设计完全指南
  • 3个实战方案:Ruffle扩展性能调优全攻略
  • 【Multisim实战指南】工具栏全解析:从入门到高效设计
  • ICLR 2026 | 多模态训练遇梯度冲突?Uni-X探索纯自回归原生多模态架构
  • 【《零基础读懂新能源汽车》—— 拆穿“省油不省钱”谎言|特斯拉/比亚迪/蔚来残值率终极对决】
  • LeafPic项目维护与贡献指南:如何参与这个开源相册的开发
  • 【开题答辩全过程】以 基于Spring框架的药品经营管理系统的设计与实现为例,包含答辩的问题和答案
  • 配置耗时从5.8秒降至83ms?揭秘MCP连接器本地数据库直连的4层内核级优化策略,限内部团队验证版
  • 3步搞定多语言情感分析:twitter-xlm-roberta终极实战指南
  • Furnace性能优化技巧:10个方法让你的追踪器运行更流畅
  • 重新定义编程思维:范畴论的系统性实践指南
  • DanKoe 视频笔记:生产力大师课:最大化生产力的三部分日常例行程序