You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何在std::lock_guard前调用std::lock?结合《C++并发编程实战》示例

为什么要在std::lock_guard之前调用std::lock?

嘿,这个问题抓得特别准!咱们得先从死锁的本质说起——当两个线程各自攥着一个互斥量,同时死死等着对方释放另一个的时候,死锁就找上门了。

先看如果不用std::lock会咋样:要是你直接写两个std::lock_guard,比如先lock_guard<std::mutex> lock_a(lhs.m),再lock_guard<std::mutex> lock_b(rhs.m),那万一有另一个线程在执行swap的时候,先锁rhs.m再锁lhs.m,就会出现经典的死锁场景:线程A握着lhs的锁等rhs的锁,线程B握着rhs的锁等lhs的锁,俩谁也动不了。

那std::lock是干啥的?它是标准库专门用来同时锁定多个互斥量的函数,内部实现了避免死锁的算法(比如会按照某种固定的顺序去尝试获取锁,或者用循环加try_lock的方式),能保证要么把所有传入的互斥量都锁定,要么一个都不锁(继续等待或者处理),绝对不会出现只锁住一部分的情况——这就从根源上掐死了死锁的可能。

那std::lock_guard在这里的角色又是什么?它是RAII风格的工具,负责自动释放互斥量。你想啊,要是手动解锁,万一中间抛出异常,或者你忘了写解锁代码,那互斥量就永远锁着了。lock_guard构造的时候接管互斥量,析构的时候自动解锁,完美解决这个问题。

不过这里要注意代码里的细节:lock_guard用了std::adopt_lock这个参数!意思是“这个互斥量我已经锁住了,你就别再尝试锁了,直接接管它的释放工作就行”。如果不用这个参数,lock_guard构造时会再次尝试锁定已经被std::lock锁住的互斥量,这属于重复锁定,会触发未定义行为,那可就麻烦大了。

再把逻辑串一遍:

  • 先调用std::lock(lhs.m, rhs.m):安全地同时锁住两个互斥量,避免死锁
  • 再用带adopt_lock的lock_guard分别接管两个互斥量:保证后续不管是正常执行完还是抛出异常,互斥量都会被正确释放
  • 最后放心地交换数据就行,完全不用操心锁的问题

内容的提问来源于stack exchange,提问作者Eduard Rostomyan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:49:07