C++中std::lock怎么锁定多个互斥量_C++多线程防死锁标准用法【并发】

2次阅读

std::lock能安全同时锁定多个互斥量并避免死锁,需配合std::defer_lock构造的std::unique_lock使用,不支持裸mutex或std::lock_guard,且异常安全自动回滚。

C++中std::lock怎么锁定多个互斥量_C++多线程防死锁标准用法【并发】

std::lock 能同时锁多个 std::mutex,且自动避免死锁

它不是简单地按顺序调用 lock(),而是用“升级锁”策略(如试探性加锁 + 退避重试)确保所有互斥量最终都能成功获取,不会因加锁顺序不一致导致死锁。这是 c++11 引入的防死锁标准方案,比手写 try_lock() 循环靠谱得多。

必须配合 std::defer_lock 使用,否则编译失败

std::lock 要求传入的互斥量处于“未持有锁”状态;如果直接传入已 lock() 的 std::mutex,行为未定义。所以得先用 std::defer_lock 构造 std::unique_lock,再把它们交给 std::lock

std::mutex m1, m2; std::unique_lock lk1(m1, std::defer_lock); std::unique_lock lk2(m2, std::defer_lock); std::lock(lk1, lk2); // ✅ 安全加锁
  • 不能写 std::lock(m1, m2) —— std::lock 只接受可锁定对象(如 std::unique_lock),不接受裸 std::mutex
  • 也不能先 m1.lock(); std::lock(lk1, lk2) —— lk1 此时已持锁,std::lock 会抛 std::system_error(错误码为 resource_deadlock_would_occur

std::lock_guard 不支持 std::lock,必须用 std::unique_lock

std::lock_guard 构造即加锁、析构即释放,不可手动控制加锁时机,因此无法与 std::lock 配合。唯一可行路径是:

  • 全部改用 std::unique_lock + std::defer_lock
  • 调用 std::lock(lk1, lk2, ...)
  • 后续可安全使用 lk1.owns_lock() 判断、lk1.unlock() 手动释放(但通常不需要)

注意:一旦 std::lock 成功返回,所有 std::unique_lock 就都已持锁,且保证无死锁 —— 这是它和手写逻辑最本质的区别。

立即学习C++免费学习笔记(深入)”;

异常安全:std::lock 失败时自动回滚已锁的互斥量

如果在尝试锁多个互斥量过程中某一步失败(例如被信号中断或系统资源不足),std::lock 会自动对已成功加锁的那些调用 unlock(),确保不留半把锁。这意味着你无需 try-catch 包裹 std::lock 来做清理 —— 它自己搞定。

  • 但要注意:std::lock 本身可能抛 std::system_error(如 operation_not_permitted),虽然极少发生
  • 真正要小心的是锁住之后、业务逻辑里抛异常 —— 这时候依赖 std::unique_lock 的 RAII 自动析构才关键

多互斥量场景下,漏掉 std::defer_lock 或误用 std::lock_guard 是最常踩的坑,这两处一错,死锁或编译失败就立刻出现。

text=ZqhQzanResources