template< class… MutexTypes > class scoped_lock;
C++17提供了新的RAII类模板std::scoped_lock<>。std:: scoped_lock<>和std::lock_guard<>完全等价,只不过前者是可变参数模板(variadic template),接收各种互斥型别作为模板参数列表,还以多个互斥对象作为构造函数的参数列表,它在作用域块的存在期间占有一或多个互斥。
创建 scoped_lock 对象时,它试图取得给定互斥的所有权。控制离开创建 scoped_lock 对象的作用域时,析构 scoped_lock 并以逆序释放互斥。若给出数个互斥,则使用免死锁算法,如同以 std::lock 。
scoped_lock 类不可复制。
假定我们需要同时获取多个锁,那么std::lock()函数和std::scoped_lock<>模板即可帮助防范死锁。
1、运用std::lock()函数和std::lock_guard<>类模板,进行内部数据的互换
-
C++标准库提供了std::lock()函数。它可以同时锁住多个互斥,而没有发生死锁的风险
-
调用std::lock()锁定两个互斥①,并依据它们分别构造std::lock_guard实例②③。我们除了用互斥充当这两个实例的构造参数,还额外提供了std::adopt_lock对象,以指明互斥已被锁住,即互斥上有锁存在,std::lock_guard实例应当据此接收锁的归属权,不得在构造函数内试图另行加锁。
//lock_guard std::lock(lhs.lock,rhs.lock); ⇽--- ① std::lock_guard<std::mutex> lock_a(lhs.lock, std::adopt_lock); ⇽--- ② std::lock_guard<std::mutex> lock_b(rhs.lock, std::adopt_lock); ⇽--- ③ swap(lhs.value,rhs.value);
//unique_lock std::unique_lock<std::mutex> lock_a(lhs.lock,std::defer_lock); ⇽--- 传入std::defer_lock实例,从而使互斥在完成构造时处于无锁状态 std::unique_lock<std::mutex> lock_b(rhs.lock,std::defer_lock); ⇽--- ①实例std::defer_lock将互斥保留为无锁状态 std::lock(lock_a,lock_b); ⇽--- ②到这里才对互斥加锁 swap(lhs.value,rhs.value);
2、利用std::lock_guard<>类模板
- C++17具有隐式类模板参数推导(implicit class template parameter deduction)机制,依据传入构造函数的参数对象自动匹配①,选择正确的互斥型别
std::scoped_lock guard(lhs.lock,rhs.lock); ⇽--- ① //等价于std::scoped_lock<std::mutex,std::mutex> guard(lhs.lock,rhs.lock); swap(lhs.value,rhs.value);