std::lock_guard和std::adopt_lock行为,不锁定互斥锁



我一直在学习std::lockstd::lock_guard的用法,大多数示例遵循以下模式:

std::lock(m1, m2);
std::lock_guard<std::mutex> guard1(m1, std::adopt_lock);
std::lock_guard<std::mutex> guard2(m2, std::adopt_lock);
//Do something here

然后我遇到了一个例子,它使用了您在使用std::unique_lock时使用的相同模式,但使用lock_guard:

std::lock_guard<std::mutex> guard1(m1, std::adopt_lock);
std::lock_guard<std::mutex> guard2(m2, std::adopt_lock);
std::lock(m1, m2);
//Do something here

我的问题是,如果您使用第二种模式并且在到达std::lock之前发生异常,这会导致未定义的行为吗?

注:我知道c++ 17引入了std::scoped_lock,std::lock_guard主要是为了与旧代码兼容。

第二个例子是未定义行为;adopt_lock构造函数假定互斥锁已经被持有。此UB在构造时触发,而不是在销毁或抛出异常时触发。


如果你用unique_lock代替scoped_lock,它有一个:

unique_lock( mutex_type& m, std::defer_lock_t t ) noexcept;

构造函数,它允许您使用std::lock,只需稍微更改:

std::unique_lock<std::mutex> guard1(m1, std::defer_lock);
std::unique_lock<std::mutex> guard2(m2, std::defer_lock);
std::lock(guard1, guard2);

现在,unique_lock会跟踪它是否有锁,所以可能会有内存和性能开销;如果unique_locks是局部作用域,如果可以证明它是安全的,编译器可以并且将其优化。

如果编译器不能证明它是安全的,那么它通常是不安全的。

最新更新