使用std::adopt_lock构造的std::lock_guard是否会释放互斥量?
问题结论
- 使用
std::adopt_lock构造的std::lock_guard一定会在析构时调用对应互斥量的unlock()方法释放锁,这是C++标准明确规定的行为。
测试代码行为说明
你观测到fun1中的std::unique_lock调用owns_lock()返回true,不代表它真的持有互斥锁,你的代码本身触发了未定义行为,核心问题有两个:
std::mutex本身是不可重入互斥量,同一时间只能被持有一次- 你同时让两个RAII锁对象(
fun1的std::unique_lock、fun2的std::lock_guard)都认为自己持有同一个互斥量m的所有权:std::adopt_lock的语义是:调用方已经提前锁定了互斥量,将锁的所有权转交给当前构造的RAII对象,RAII对象不需要再执行加锁操作,只需要在析构时自动解锁- 当
fun2执行结束,std::lock_guard析构,已经直接调用m.unlock()释放了互斥锁 std::unique_lock的owns_lock()方法只会读取对象内部存储的「是否持有锁」的标记,不会同步查询底层互斥量的实际状态,所以才会返回true,但此时互斥锁实际已经处于未锁定状态,如果后续调用unique_lock的unlock()方法,会对已经释放的互斥量重复解锁,直接触发程序崩溃等不可预期问题。
std::adopt_lock的正确使用场景 它的设计目的是解决「已经手动加锁,需要用RAII对象自动管理锁释放」的场景,同一时间只能有一个RAII对象持有同一个互斥量的所有权,示例如下:
std::mutex m; // 提前手动加锁 m.lock(); // 把锁的所有权交给lock_guard,后续不需要手动解锁 std::lock_guard<std::mutex> guard(m, std::adopt_lock); // 作用域结束后lock_guard自动析构解锁
内容的提问来源于stack exchange,提问作者Huy Nhat Tran
相关产品推荐
相关产品推荐

