lock_guard 是 c++11 raii 锁管理器,构造时自动加锁、析构时自动解锁,避免手动 lock/unlock 遗漏导致死锁;仅支持栈上创建、不可复制/移动,作用域结束即释放锁。

lock_guard 是什么,为什么不用手动 lock/unlock
lock_guard 是 C++11 引入的 RAII(资源获取即初始化)锁管理器,它在构造时自动调用 mutex.lock(),析构时自动调用 mutex.unlock()。不用它的话,容易漏写 unlock()(比如函数提前 return、抛异常),导致死锁或资源永久占用。
它不支持转移(move)、不支持复制,只支持栈上创建 —— 这正是它的设计意图:作用域一结束,锁立刻释放。
基本用法:声明位置决定加锁范围
必须在需要保护的临界区**最开始**、且**同一作用域内**声明 lock_guard,否则起不到保护作用。
- ✅ 正确:在 if 分支开头、循环体开头、函数开头声明,锁覆盖整个作用域块
- ❌ 错误:在 if 内部声明但作用域外还有共享访问;或声明后又手动
unlock()(会触发未定义行为) - ⚠️ 注意:
lock_guard构造函数是阻塞的,如果 mutex 已被占用,线程会挂起等待
示例:
立即学习“C++免费学习笔记(深入)”;
std::mutex mtx;
void safe_increment() {
std::lock_guard<std::mutex> guard(mtx); // 构造即加锁
counter++; // 临界区
} // guard 析构,自动 unlock —— 即使这里 throw 异常也安全
常见错误:传错类型、跨作用域、误用 try_lock
lock_guard 只接受可 lock() 的互斥体类型(如 std::mutex、std::recursive_mutex),不支持 std::shared_mutex 或带超时的 std::timed_mutex(后者要用 std::unique_lock)。
- ❌
std::lock_guard<:shared_mutex> guard(shmtx)</:shared_mutex>→ 编译失败,shared_mutex没有lock()成员(只有lock_shared()/lock()) - ❌ 把
lock_guard声明在函数参数里(如void f(std::lock_guard<:mutex> g)</:mutex>)→ 构造发生在调用前,但析构在函数返回后,锁范围失控 - ❌ 试图用
try_to_lock标签:它不支持该模式,要非阻塞加锁请换std::unique_lock+std::defer_lock或std::try_to_lock
和 unique_lock 的关键区别在哪
多数简单场景用 lock_guard 就够了;只有当你需要延迟加锁、手动解锁、转移所有权、或配合条件变量时,才必须用 std::unique_lock。
-
lock_guard:轻量、不可复制/移动、构造即锁、析构即放 —— 安全、高效、意图明确 -
unique_lock:更灵活但稍重,支持unlock()、try_lock()、release(),且能和std::condition_variable配合 - 性能差异很小,但滥用
unique_lock(比如只是想自动解锁)会让代码意图模糊,也增加出错可能
真正容易被忽略的是:即使你只读共享数据,只要其他线程可能写它,就必须加锁 —— lock_guard 不区分读写,它只管“有没有人在动这个资源”。











