我找到了以下两段代码:
http://en.cppreference.com/w/cpp/thread/lock
void assign_lunch_partner(Employee &e1, Employee &e2) { // use std::lock to acquire two locks without worrying about // other calls to assign_lunch_partner deadlocking us { // m is the std::mutex field 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); // ... } }
http://www.amazon.com/C-Concurrency-Action-Practical-Multithreading/dp/1933988770
void swap(X& lhs, X&rhs){ if(&lhs == &rhs) return; // m is the std::mutex field std::lock(lhs.m, rhs.m); std::lock_guard<std::mutex> lock_a(lhs.m, std::adopt_lock); std::lock_guard<std::mutex> lock_b(rhs.m, std::adopt_lock); swap(lhs.some_detail, rhs.some_detail); }
我想问一下使用两个版本中的任何一个有什么区别和后果? (先锁定还是先创建std::lock_guard
或std::unique_lock
?)
最佳答案
1) 第一个代码示例
{
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;
}
这是一个标准的锁守卫,当退出作用域时,锁lk
被释放
{
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::cout << e1.id << " and " << e2.id << " got locks" << std::endl;
// ...
}
这里我们首先创建锁而不获取它们(这是 std::defer_lock
的要点),然后使用 std::lock
同时在两个锁上确保在没有死锁风险的情况下获取它们,如果函数的另一个调用者交错(如果你用对 std::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);
std::lock(lk2); // Risk of deadlock !
std::cout << e1.id << " and " << e2.id << " got locks" << std::endl;
// ...
}
2) 第二个代码示例
void swap(X& lhs, X&rhs){
if(&lhs == &rhs)
return;
// m is the std::mutex field
std::lock(lhs.m, rhs.m);
std::lock_guard<std::mutex> lock_a(lhs.m, std::adopt_lock);
std::lock_guard<std::mutex> lock_b(rhs.m, std::adopt_lock);
swap(lhs.some_detail, rhs.some_detail);
}
现在,我们首先获取锁(仍然避免死锁),然后然后创建锁守卫以确保它们被正确释放。
请注意 std::adopt_lock
要求当前线程拥有互斥锁(这是因为我们刚刚锁定了它们)
结论
这里有两种模式:
1) 同时锁定两个互斥体,然后创建守卫
2) 创建守卫,然后同时锁定两个互斥锁
两种模式是等价的,目的是相同的:同时安全地锁定两个互斥体,并确保解锁总是发生在两者上。
至于std::lock_guard
和std::unique_lock
的区别,你应该看到this other SO post ,大多数时候 std::lock_guard
就足够了。
关于c++ - 第一次锁定和创建 lock_guard(adopt_lock) 和创建 unique_lock(defer_lock) 和锁定有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27089434/