CppCoreGuidelines CP.21 用 std::lock() 或 std::scoped_lock 获取多个互斥锁
25 June 2023
“Use std::lock() or std::scoped_lock to acquire multiple mutexes”
理由
例子
以下例子会导致死锁:
// thread 1 lock_guard<mutex> lck1(m1); lock_guard<mutex> lck2(m2); // thread 2 lock_guard<mutex> lck2(m2); lock_guard<mutex> lck1(m1);
应该使用 lock()
:
// thread 1 lock(m1, m2); lock_guard<mutex> lck1(m1, adopt_lock); lock_guard<mutex> lck2(m2, adopt_lock); // thread 2 lock(m2, m1); lock_guard<mutex> lck2(m2, adopt_lock); lock_guard<mutex> lck1(m1, adopt_lock);
或者用 C++17 的机制:
// thread 1 scoped_lock<mutex, mutex> lck1(m1, m2); // thread 2 scoped_lock<mutex, mutex> lck2(m2, m1);
这里,开发 thread1
和 thread2
的人仍然没有协调互斥锁的顺序,但是顺序已经不重要。
注意
在实际代码中,互斥锁的名字不一定能告诉程序员它的使用目的,以及获取顺序。在实际代码中,互斥锁并不总是在连续的几行代码中获取。
在 C++17 中,可以简单的这样写:
lock_guard lck1(m1, adopt_lock);
然后,就能推导出互斥锁的类型。
强化
检测出捕获多个互斥锁的地方。尽管不太好判断,但是捕捉前面介绍的简单例子相对还方便。