lock_guard 是栈上自动管理互斥量生命周期的 RaiI 类模板,构造时加锁、析构时解锁,确保异常安全;不能 new、不能 return、不能作类成员,因其禁止拷贝/移动且依赖栈对象生命周期。

lock_guard 是什么,为什么不能直接 new 或 return
lock_guard 是一个栈上自动管理互斥量生命周期的 RAII 类模板,它在构造时加锁、析构时解锁。它的核心价值不是“加锁”,而是“确保锁一定被释放”——哪怕中间抛异常、提前 return 或 goto 跳出作用域,析构函数仍会被调用。
所以你不能:
– new lock_guard:堆分配对象不会自动析构
– return lock_guard:返回临时对象会触发移动/拷贝,而 lock_guard 明确删除了拷贝和移动构造函数(编译报错:use of deleted function)
– 把它作为类成员变量长期持有:它不拥有 mutex,也不负责管理其生命周期,只管“这一段代码执行期间”的锁定
最常用写法:在作用域开头声明,配合 std::mutex 使用
典型场景是保护共享数据读写。比如多个线程往同一个 std::vector 里 push:
std::mutex mtx; std::vector data; void thread_func() { // 加锁范围仅限于访问 data 的这几行 std::lock_guard guard(mtx); data.push_back(42); // guard 离开作用域,自动 unlock() }
注意:
– guard 必须声明在需要保护的代码之前,且作用域要严格包裹临界区
– 不要手动调用 guard.unlock():它没这个接口,也不该有
– 如果临界区很长或包含可能 throw 的操作,lock_guard 依然安全
和 unique_lock 对比:什么时候不该用 lock_guard
lock_guard 是最轻量、最严格的自动锁,但灵活性差。遇到以下情况,就得换 std::unique_lock:
- 需要延迟加锁(构造时不锁,后面再
lock()) - 需要手动控制解锁时机(比如先 unlock 再做耗时 IO,避免阻塞其他线程)
- 要和条件变量
std::condition_variable配合使用(wait()要求传入unique_lock) - 要转移锁的所有权(比如放进
std::move返回值中)
lock_guard 没有 unlock()、try_lock()、release() 这些方法,也没提供底层 mutex* 访问接口——它就是为“进作用域即锁、出作用域即放”这个单一语义设计的。
立即学习“C++免费学习笔记(深入)”;
容易忽略的细节:类型必须匹配,且 mutex 不能是临时对象
lock_guard 模板参数类型必须和传入的互斥量类型完全一致。常见错误:
std::recursive_mutex rm; std::lock_guard guard(rm); // ❌ 编译失败:类型不匹配
正确写法是:
std::lock_guard guard(rm); // ✅
另一个坑是传入临时 mutex:
std::lock_guard guard(std::mutex{}); // ❌ 构造完就销毁 mutex,guard 锁的是已析构对象
所有 mutex 实例必须是静态、全局、类成员或栈上持久存在的对象。