[C++] lock_guard、unique_lock与条件变量wait()函数

一、引言

本文主要讨论 lock_guard、unique_lock的区别,以及条件变量使用wait函数时为什么不能使用lock_guard的原因

二、lock_guard、unique_lock的核心区别

cpp 复制代码
        std::unique_lock<std::mutex> lock(q_mutex); // unique_lock可以解锁
//        std::lock_guard<std::mutex> lock(q_mutex); //会发生报错,qt编译不通过,因为lock_guard只能锁定一次,不能解锁,知道析构,

2.1 lock_guard

lock_guard的对象是构造完毕后就上锁完毕获取到锁了,直到析构时才会解锁。(这里如果读起来很拗口难懂,可以先看看我另外一篇博客中关于"上锁、解锁、获取锁、释放锁的几个概念区别")在这期间,lock_guard是不能解锁的

2.2 unique_lock

unique_lock可以随时随地地unlock()与lock(),这样也就更加地灵活。

这里附加上gpt总结完整表格

特性 std::lock_guard std::unique_lock
可解锁性 不可手动解锁(构造即锁,析构即解) 可随时 unlock()/lock()
灵活性 轻量级,单一职责 功能强大,状态可管理
使用场景 简单临界区保护 条件变量、延迟锁定、手动解锁
性能开销 零额外开销(纯 RAII) 略高(维护锁定状态,多1-2字节)
能否与 wait() 配合 绝对不能 必须使用
构造函数 lock_guard(mutex) unique_lock(mutex)unique_lock

三、为什么 condition_variable::wait()必须用unique_lock?

wait()函数中会走三个步骤:

调用 wait() 时,内部执行不可分割的序列:

  1. unlock(mutex) :释放锁,让其他线程能修改共享状态
  2. block(wait_queue) :线程进入等待队列,挂起
  3. lock(mutex) :被唤醒后,重新获取锁,才返回继续执行

lock_guard的致命缺陷也就是在这里,使用wait()函数核心目的就是阻塞某个线程等待某个条件达到后再让这个线程运行下去,但是lock_guard只有析构时才可以解锁。如果wait()函数中lock_guard一直不解锁,那么其他线程就无法获取这个锁,也就是说其他 线程会被一直阻塞住。

四、应用时机与场景

下面是一些应用场景的ai总结

场景 A:简单临界区 → lock_guard

cpp 复制代码
void simple_update() {
    std::lock_guard<std::mutex> lock(mtx);
    shared_data = 42;
}  // 自动解锁

场景 B:条件变量 → unique_lock

cpp 复制代码
void conditional_wait() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, [&]{ return ready; });  // 需要解锁/重新锁
    // 获取数据
}

场景 C:延迟锁定 → unique_lock

cpp 复制代码
std::unique_lock<std::mutex> lock(mtx, std::defer_lock);  // 暂不锁定
// ... 一些不需要锁的操作 ...
lock.lock();  // 现在锁定
// ... 临界区 ...

五、黄金法则

  1. 默认用 lock_guard:除非有特殊需求
  2. 需要 wait() 时用 unique_lock :这是唯一强制场景
  3. 不要手动 mutex.lock()/unlock():易忘解锁导致死锁
  4. wait() 函数中返回 true 就放行 :Lambda 返回 true 停止等待
相关推荐
阿pin1 分钟前
Android随笔-View绘制流程
android·开发语言·view
敖行客 Allthinker26 分钟前
IM 融合专题:后端架构师的核心修炼
java·开发语言·数据库
进击的程序猿~31 分钟前
Go Slice源码深度解析指南
开发语言·后端·golang
Hesionberger35 分钟前
快速求解完全平方数的最少数量
开发语言·数据结构·python·算法·leetcode·c#
c2385635 分钟前
《序列 DP:C++ 中的“最长”套路与编辑距离》
c++·算法·动态规划
鱼子星_38 分钟前
【C++】类和对象(下)——初始化列表,类型转换,static成员,友元,内部类,匿名对象,编译器的优化拓展
c语言·c++·笔记
王老师青少年编程9 小时前
2025年【江苏“信息与未来”编程思维】真题及题解(T2:坐标变换)
c++·题解·真题·坐标变换·编程思维·江苏·信息与未来
西门吹-禅11 小时前
java springboot N+1问题
java·开发语言·spring boot
skywalk816311 小时前
设计并实现段言的 C FFI 绑定机制 @Trae
c语言·开发语言·python·编程
2023自学中12 小时前
C++ 内存追踪器
linux·c++