std::scoped_lock
定义于头文件 <mutex>
|
||
template< class... MutexTypes > class scoped_lock; |
(C++17 起) | |
类 scoped_lock
是提供便利 RAII 风格机制的互斥包装器,它在作用域块的存在期间占有一或多个互斥。
创建 scoped_lock
对象时,它试图取得给定互斥的所有权。控制离开创建 scoped_lock
对象的作用域时,析构 scoped_lock
并以逆序释放互斥。若给出数个互斥,则使用免死锁算法,如同以 std::lock 。
scoped_lock
类不可复制。
模板形参
MutexTypes | - | 要锁定的互斥类型。类型必须满足可锁定 (Lockable) 要求,除非 sizeof...(MutexTypes)==1 ,该情况下唯一的类型必须满足基本可锁定 (BasicLockable) |
成员类型
成员类型 | 定义 |
mutex_type (若 sizeof...(MutexTypes)==1 )
|
Mutex , MutexTypes... 中的单独类型
|
成员函数
构造 scoped_lock ,可选地锁定给定的互斥 (公开成员函数) | |
析构 scoped_lock 对象,解锁底层互斥 (公开成员函数) | |
operator= [被删除] |
不可复制 (公开成员函数) |
示例
以下示例用 std::scoped_lock
锁定互斥对而不死锁,且为 RAII 风格。
运行此代码
#include <mutex> #include <thread> #include <iostream> #include <vector> #include <functional> #include <chrono> #include <string> struct Employee { Employee(std::string id) : id(id) {} std::string id; std::vector<std::string> lunch_partners; std::mutex m; std::string output() const { std::string ret = "Employee " + id + " has lunch partners: "; for( const auto& partner : lunch_partners ) ret += partner + " "; return ret; } }; void send_mail(Employee &, Employee &) { // 模拟耗时的发信操作 std::this_thread::sleep_for(std::chrono::seconds(1)); } void assign_lunch_partner(Employee &e1, Employee &e2) { static std::mutex io_mutex; { std::lock_guard<std::mutex> lk(io_mutex); std::cout << e1.id << " and " << e2.id << " are waiting for locks" << std::endl; } { // 用 std::scoped_lock 取得二个锁,而无需担心 // 其他对 assign_lunch_partner 的调用死锁我们 // 而且它亦提供便利的 RAII 风格机制 std::scoped_lock lock(e1.m, e2.m); // 等价代码 1 (用 std::lock 和 std::lock_guard ) // std::lock(e1.m, e2.m); // std::lock_guard<std::mutex> lk1(e1.m, std::adopt_lock); // std::lock_guard<std::mutex> lk2(e2.m, std::adopt_lock); // 等价代码 2 (若需要 unique_lock ,例如对于条件变量) // std::unique_lock<std::mutex> lk1(e1.m, std::defer_lock); // std::unique_lock<std::mutex> lk2(e2.m, std::defer_lock); // std::lock(lk1, lk2); { std::lock_guard<std::mutex> lk(io_mutex); std::cout << e1.id << " and " << e2.id << " got locks" << std::endl; } e1.lunch_partners.push_back(e2.id); e2.lunch_partners.push_back(e1.id); } send_mail(e1, e2); send_mail(e2, e1); } int main() { Employee alice("alice"), bob("bob"), christina("christina"), dave("dave"); // 在并行线程中指派,因为就午餐指派发邮件消耗很长时间 std::vector<std::thread> threads; threads.emplace_back(assign_lunch_partner, std::ref(alice), std::ref(bob)); threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(bob)); threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(alice)); threads.emplace_back(assign_lunch_partner, std::ref(dave), std::ref(bob)); for (auto &thread : threads) thread.join(); std::cout << alice.output() << '\n' << bob.output() << '\n' << christina.output() << '\n' << dave.output() << '\n'; }
可能的输出:
alice and bob are waiting for locks alice and bob got locks christina and bob are waiting for locks christina and alice are waiting for locks dave and bob are waiting for locks dave and bob got locks christina and alice got locks christina and bob got locks Employee alice has lunch partners: bob christina Employee bob has lunch partners: alice dave christina Employee christina has lunch partners: alice bob Employee dave has lunch partners: bob
缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
DR | 应用于 | 出版时的行为 | 正确行为 |
---|---|---|---|
LWG 2981 | C++17 | 曾提供来自 scoped_lock<MutexTypes...> 的冗余推导指引
|
已移除 |
参阅
(C++11) |
实现可移动的互斥体所有权包装器 (类模板) |
(C++11) |
实现严格基于作用域的互斥体所有权包装器 (类模板) |