std::scoped_lock
来自 cppreference.com
在头文件 <mutex> 中定义 |
||
template< class... MutexTypes > class scoped_lock; |
(自 C++17 起) | |
类 scoped_lock
是一个互斥体包装器,它提供了一种方便的 RAII 风格 机制,用于在作用域块的持续时间内拥有零个或多个互斥体。
当创建 scoped_lock
对象时,它会尝试获取给定互斥体的所有权。当控制离开创建 scoped_lock
对象的作用域时,scoped_lock
会被析构,并且互斥体会被释放。如果给出了多个互斥体,则会使用死锁避免算法,就像由 std::lock 一样。
scoped_lock
类不可复制。
内容 |
[edit] 模板参数
MutexTypes | - | 要锁定的互斥体的类型。这些类型必须满足 Lockable 要求,除非 sizeof...(MutexTypes) == 1,在这种情况下,唯一类型必须满足 BasicLockable |
[edit] 成员类型
成员类型 | 定义 |
mutex_type (有条件地存在) |
如果 sizeof...(MutexTypes) == 1,成员类型 |
[edit] 成员函数
构造一个 scoped_lock ,可以选择锁定给定的互斥体(公共成员函数) | |
析构 scoped_lock 对象,解锁底层互斥体(公共成员函数) | |
operator= [已删除] |
不可复制赋值 (公共成员函数) |
[edit] 注释
一个常见的初学者错误是“忘记”给 scoped_lock
变量命名,例如 std::scoped_lock(mtx);(它默认构造一个名为 mtx
的 scoped_lock
变量)或 std::scoped_lock{mtx};(它构造一个立即被销毁的右值对象),因此实际上并没有构造一个锁,该锁在作用域的剩余部分保持互斥体的状态。
特性测试 宏 | 值 | Std | 特性 |
---|---|---|---|
__cpp_lib_scoped_lock |
201703L | (C++17) | std::scoped_lock
|
[edit] 示例
以下示例使用 std::scoped_lock
来锁定互斥体对而不会出现死锁,并且是 RAII 风格的。
运行此代码
#include <chrono> #include <functional> #include <iostream> #include <mutex> #include <string> #include <thread> #include <vector> using namespace std::chrono_literals; struct Employee { std::vector<std::string> lunch_partners; std::string id; std::mutex m; Employee(std::string id) : id(id) {} std::string partners() const { std::string ret = "Employee " + id + " has lunch partners: "; for (int count{}; const auto& partner : lunch_partners) ret += (count++ ? ", " : "") + partner; return ret; } }; void send_mail(Employee&, Employee&) { // Simulate a time-consuming messaging operation std::this_thread::sleep_for(1s); } 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; } { // Use std::scoped_lock to acquire two locks without worrying about // other calls to assign_lunch_partner deadlocking us // and it also provides a convenient RAII-style mechanism std::scoped_lock lock(e1.m, e2.m); // Equivalent code 1 (using std::lock and 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); // Equivalent code 2 (if unique_locks are needed, e.g. for condition variables) // 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"); // Assign in parallel threads because mailing users about lunch assignments // takes a long time 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.partners() << '\n' << bob.partners() << '\n' << christina.partners() << '\n' << dave.partners() << '\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
[edit] 缺陷报告
以下行为更改缺陷报告已追溯应用于以前发布的 C++ 标准。
DR | 应用于 | 发布的行为 | 正确的行为 |
---|---|---|---|
LWG 2981 | C++17 | 从 scoped_lock<MutexTypes...> 提供了冗余的推断指南 |
已删除 |
[edit] 另请参阅
(C++11) |
实现可移动的互斥体所有权包装器 (类模板) |
(C++11) |
实现严格基于作用域的互斥体所有权包装器 (类模板) |