std::lock_guard必须与std::mutex配对使用,通过raii自动管理锁的获取和释放;它不支持延迟加锁、超时、重入或移动,多锁需用std::lock+std::adopt_lock或改用std::unique_lock。

std::mutex 必须和 std::lock_guard 配对用,不能裸用
裸调用 std::mutex::lock() 和 std::mutex::unlock() 极易出错:异常一抛,unlock() 就被跳过,锁永远卡住。这是 C++ 多线程里最常见死锁源头之一。
正确做法是让 std::lock_guard 管理生命周期——构造时自动加锁,析构时自动解锁(RAII)。
-
std::lock_guard是栈对象,作用域结束即释放锁,无需手动干预 - 它不支持拷贝,只支持移动(实际中几乎不用移动,直接定义在临界区入口就行)
- 不要把它声明在函数开头然后“跨多个逻辑块”复用;每个需要保护的代码段,各自配一个
std::lock_guard
std::mutex mtx;
int counter = 0;
void increment() {
std::lock_guard<std::mutex> lock(mtx); // ✅ 自动加锁/解锁
++counter;
} // lock 析构,自动 unlock
std::lock_guard 构造失败会抛 std::system_error,不是返回码
如果传入的 std::mutex 已被当前线程持有(比如递归锁没用 std::recursive_mutex),std::lock_guard 构造时会直接抛 std::system_error,错误码通常是 resource_deadlock_would_occur。
- 这不是 warning,是未捕获就 crash 的异常,必须处理或确保不会发生
- 别指望它“静默失败”,C++ 标准库的互斥量默认不支持重入
- 若真需要同一线程多次加锁,换用
std::recursive_mutex+std::lock_guard<:recursive_mutex></:recursive_mutex>
std::lock_guard 不支持延迟加锁或超时,要等就用 std::unique_lock
std::lock_guard 只有最简构造形式:std::lock_guard(mutex),它必须立即成功加锁,否则抛异常。没法试锁、没法设超时、没法后续手动 unlock。
立即学习“C++免费学习笔记(深入)”;
- 需要
try_lock()?用std::unique_lock+try_lock()方法 - 需要带超时的
try_lock_for()或try_lock_until()?只能用std::unique_lock - 需要把锁“转移”给另一个作用域(比如返回锁对象)?
std::unique_lock支持移动,std::lock_guard不支持
std::mutex mtx;
std::unique_lock<std::mutex> lock(mtx, std::defer_lock); // ✅ 延迟加锁
if (lock.try_lock_for(std::chrono::milliseconds(100))) {
// 成功拿到锁
}
多个 mutex 加锁顺序不一致,死锁风险极高
两个线程分别按不同顺序调用 std::lock_guard 锁两个 mutex,是经典死锁场景。比如线程 A 先锁 mtx_a 再锁 mtx_b,线程 B 反过来,就可能互相卡住。
-
std::lock_guard本身不解决顺序问题,它只管单个 mutex - 多锁场景下,必须全局约定加锁顺序(比如总是按地址大小排序),或统一用
std::lock(mtx_a, mtx_b)批量加锁(它内部用死锁避免算法) - 配合
std::lock_guard用批量加锁时,要搭配std::adopt_lock:
std::mutex mtx_a, mtx_b; std::lock(mtx_a, mtx_b); // ✅ 原子性加锁两个 std::lock_guard<std::mutex> guard_a(mtx_a, std::adopt_lock); std::lock_guard<std::mutex> guard_b(mtx_b, std::adopt_lock);
忘了统一加锁顺序,或者漏了 std::adopt_lock,程序可能当场崩溃或行为未定义。










