std::lock
来自cppreference.com
在标头 <mutex> 定义 | ||
template<class Lockable1, class Lockable2, class... LockableN> void lock( Lockable1& lock1, Lockable2& lock2, LockableN&... lockn); | (C++11 起) | |
锁定给定的可锁定(Lockable) 对象 lock1、lock2、...
、lockn
,使用免死锁算法以避免死锁。
对象被一系列未指定的 lock
、try_lock
和 unlock
调用锁定。若调用 lock
或 unlock
导致异常,则在重抛前对任何已锁的对象调用 unlock
。
目录 |
[编辑]参数
lock1, lock2, ... , lockn | - | 要锁定的可锁定(Lockable) 对象 |
[编辑]返回值
(无)
[编辑]注解
Boost 提供此函数的一个版本,它接收以一对迭代器定义的可锁定(Lockable) 对象的序列。
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 ="雇员 "+ id +" 的午餐伙伴: ";for(auto n{lunch_partners.size()};constauto& partner : lunch_partners) ret += partner +(--n ?", ":"");return ret;}}; void send_mail(Employee &, Employee &){// 模拟耗时的发信操作std::this_thread::sleep_for(std::chrono::milliseconds(696));} void assign_lunch_partner(Employee& e1, Employee& e2){staticstd::mutex io_mutex;{std::lock_guard<std::mutex> lk(io_mutex);std::cout<< e1.id<<" 和 "<< e2.id<<" 正等待锁定"<<std::endl;} // 用 std::lock 获得两个锁,而不担心对 assign_lunch_partner 的其他调用会死锁我们{ 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);// 等价代码(若需要 unique_locks ,例如对于条件变量)// 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);// C++17 中可用的较优解法// std::scoped_lock lk(e1.m, e2.m);{std::lock_guard<std::mutex> lk(io_mutex);std::cout<< e1.id<<" 和 "<< e2.id<<" 获得了锁"<<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 和 Bob 正等待锁定 Alice 和 Bob 获得了锁 Christina 和 Bob 正等待锁定 Christina 和 Bob 获得了锁 Christina 和 Alice 正等待锁定 Dave 和 Bob 正等待锁定 Dave 和 Bob 获得了锁 Christina 和 Alice 获得了锁 雇员 Alice 的午餐伙伴: Bob, Christina 雇员 Bob 的午餐伙伴: Alice, Christina, Dave 雇员 Christina 的午餐伙伴: Bob, Alice 雇员 Dave 的午餐伙伴: Bob
[编辑]参阅
(C++11) | 实现可移动的互斥体所有权包装器 (类模板) |
(C++11) | 尝试通过重复调用 try_lock 获得互斥体的所有权 (函数模板) |
(C++17) | 用于多个互斥体的免死锁 RAII 封装器 (类模板) |