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

thread 的mutex优化

std::mutex mtx;
int shared_data = 0;void increment() {std::lock_guard<std::mutex> lock(mtx);  // 自动加锁shared_data++;  // 临界区
}  // 离开作用域时自动解锁

std::lock_guard 在离开作用域时自动解锁的行为是基于 C++ 的 RAII (Resource Acquisition Is Initialization) 设计模式实现的。这种模式将资源的生命周期与对象的生命周期绑定,确保资源在对象析构时自动释放。

RAII 机制解析

当你创建一个 std::lock_guard 对象时:

  1. 构造函数:在对象创建时立即获取锁(调用 mutex::lock()
  2. 析构函数:在对象生命周期结束时自动释放锁(调用 mutex::unlock()
template <typename Mutex>
class lock_guard {
public:explicit lock_guard(Mutex& m) : mtx(m) {mtx.lock();  // 构造时加锁}~lock_guard() {mtx.unlock();  // 析构时解锁}private:Mutex& mtx;  // 引用底层互斥锁
};

作用域规则与对象生命周期

C++ 规定,局部对象在离开其定义的作用域时会自动析构。例如:

void func() {// 进入作用域{  // 子作用域开始std::lock_guard<std::mutex> lock(mtx);  // 构造 + 加锁// 临界区}  // 子作用域结束 → lock 对象析构 → 自动解锁// lock 对象在此处已不存在
}  // 函数结束 → 所有局部对象析构

为什么这种设计更安全?

对比手动管理锁的方式:

// 手动管理锁(不推荐)
void increment() {mtx.lock();  // 手动加锁try {shared_data++;  // 临界区// 如果此处抛出异常,锁将不会被释放} catch (...) {mtx.unlock();  // 需要在每个异常处理路径中解锁throw;}mtx.unlock();  // 手动解锁(必须确保执行)
}

手动管理锁的问题:

  1. 容易遗漏解锁:如果临界区中有多个 return 语句或异常抛出
  2. 代码冗余:每个锁都需要配套的解锁操作
  3. 难以维护:修改临界区逻辑时可能忘记调整解锁位置

RAII 的优势

使用 std::lock_guard 的好处:

  1. 自动解锁:无论临界区如何退出(正常返回或异常),锁都会被释放
  2. 代码简洁:无需显式编写 unlock 语句
  3. 异常安全:即使发生异常,资源也能正确释放
  4. 防止死锁:锁的持有时间严格限定在作用域内

扩展:更灵活的 std::unique_lock

std::unique_lock 是比 std::lock_guard 更灵活的锁管理工具,支持延迟加锁、锁的转移和定时锁等功能:

void func() {std::unique_lock<std::mutex> lock(mtx, std::defer_lock);  // 构造时不加锁// 执行一些无需锁的操作lock.lock();  // 手动加锁// 临界区lock.unlock();  // 手动解锁(可以提前释放锁)// 执行一些无需锁的操作lock.lock();  // 再次加锁// 临界区
}  // 离开作用域时,如果锁是锁定状态,则自动解锁

类似的还有微软自己提供的event 关键代码段,都是需要在各种异常退出函数是手动释放,十分繁琐,切容易遗漏。

总结

std::lock_guard 之所以能自动解锁,是因为:

  1. 它基于 RAII 模式设计
  2. 构造时获取锁,析构时释放锁
  3. C++ 保证局部对象在离开作用域时自动析构

这种设计使得锁的管理更加安全、简洁,避免了手动管理锁时常见的资源泄漏问题。

http://www.xdnf.cn/news/7637.html

相关文章:

  • 基于FFT变换的雷达信号检测和参数估计matlab性能仿真
  • 每日两道leetcode(今天开始刷基础题模块——这次是之前的修改版)
  • ES 调优帖:关于索引合并参数 index.merge.policy.deletePctAllowed 的取值优化
  • 数字展厅是什么?怎样实现数字展厅的落地?
  • matlab编写的BM3D图像去噪方法
  • SpringBoot-4-Spring Boot项目配置文件和日志配置
  • 电子制造企业智能制造升级:MES系统应用深度解析
  • centos7安装mysql8.0
  • Android trace presentFence屏幕显示的帧
  • sgRNA的靶基因基因组如何获得? for 下游的 T7E1验证
  • 不同的二叉搜索树 II:动态规划与递归构造
  • JavaScript作用域和作用域链
  • web开发全过程总结
  • 创建一个使用 GPT-4o 和 SERP 数据的 RAG 聊天机器人
  • deepseek梳理java高级开发工程师es面试题
  • 1.3 C++之变量与数据类型
  • Vue百日学习计划Day43-45天详细计划-Gemini版
  • Jenkins+Docker+Harbor快速部署Spring Boot项目详解
  • sv数据格式转换
  • 【氮化镓】低剂量率对GaN HEMT栅极漏电的影响
  • 2025年第十一届传感器、机电一体化和自动化系统国际学术研讨会(ISSMAS 2025)
  • 景区卡机数据报表-跨服务查看数据教程——诸天万界相连—仙盟创梦IDE
  • docker容器知识
  • 宿州金博学校开展防震演练:夯实安全根基,守护校园平安
  • java redis set 集合操作中 如何有效移除自定义对象
  • 深信服golang面经
  • 【Python 算法零基础 4.排序 ③ 插入排序】
  • 零基础入门Selenium自动化测试:自动登录edu邮箱
  • waitress 简介
  • Dify实战案例《AI面试官》更新,支持语音交互+智能知识库+随机题库+敏感词过滤等...