std::lock
来自 cppreference.com
在头文件 <mutex> 中定义 |
||
template< class Lockable1, class Lockable2, class... LockableN > void lock( Lockable1& lock1, Lockable2& lock2, LockableN&... lockn ); |
(自 C++11 起) | |
使用死锁避免算法来避免死锁,锁定给定的 可锁定 对象 lock1、lock2、...
、lockn。
这些对象通过对 lock
、try_lock
和 unlock
的一系列未指定的调用来锁定。如果对 lock
或 unlock
的调用导致异常,则在重新抛出之前,将对任何已锁定对象调用 unlock
。
内容 |
[编辑] 参数
lock1、lock2、...、lockn | - | 要锁定的 可锁定 对象 |
[编辑] 返回值
(无)
[编辑] 备注
Boost 提供了此函数的版本,它接受由一对迭代器定义的 可锁定 对象序列。
std::scoped_lock 为此函数提供了一个 RAII 包装器,通常比对 std::lock
的裸调用更可取。
[编辑] 示例
以下示例使用 std::lock
来锁定互斥锁对,而不会发生死锁。
运行此代码
#include <chrono> #include <functional> #include <iostream> #include <mutex> #include <string> #include <thread> #include <vector> 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 (auto n{lunch_partners.size()}; const auto& partner : lunch_partners) ret += partner + (--n ? ", " : ""); return ret; } }; void send_mail(Employee&, Employee&) { // Simulate a time-consuming messaging operation std::this_thread::sleep_for(std::chrono::milliseconds(696)); } 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::lock to acquire two locks without worrying about // other calls to assign_lunch_partner deadlocking us { 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 (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); // Superior solution available in C++17 // std::scoped_lock lk(e1.m, e2.m); { 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.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 Bob got 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 Employee Alice has lunch partners: Bob, Christina Employee Bob has lunch partners: Alice, Christina, Dave Employee Christina has lunch partners: Bob, Alice Employee Dave has lunch partners: Bob
[编辑] 参见
(C++11) |
实现可移动的互斥锁所有权包装器 (类模板) |
(C++11) |
尝试通过重复调用 try_lock 来获取互斥锁的所有权(函数模板) |
(C++17) |
用于多个互斥锁的死锁避免 RAII 包装器 (类模板) |