unique_lock是一个通用的互迟锁包装类,它允许延迟锁定,限时尝试加锁,递归锁定,锁定所有权的转移以及与条件变量一起使用。
简单地讲,unique_lock 是 lock_guard 的升级加强版,它具有 lock_guard 的所有功能,同时又具有其他很多方法,使用起来更强灵活方便,能够应对更复杂的锁定需要。
特点如下:
-
创建后默认锁定,和lock_guard
-
创建时可以不锁定(通过指定第二个参数为std::defer_lock),而在需要时再锁定。defer_lock表示延时加锁的意思
-
可以随时加锁解锁,lock_guard没有提供加解锁的函数。
-
作用域规则同 lock_grard,析构时自动释放锁
-
不可复制,可移动
-
条件变量需要该类型的锁作为参数(此时必须使用unique_lock)
-
try_lock尝试加锁,try_lock_until限时尝试加锁
示例代码:
#include <mutex>
#include <thread>
#include <chrono>
struct Box {
explicit Box(int num) : num_things{num} {}
int num_things;
std::mutex m;
};
void transfer(Box &from, Box &to, int num)
{
// don't actually take the locks yet
std::unique_lock<std::mutex> lock1(from.m, std::defer_lock);
std::unique_lock<std::mutex> lock2(to.m, std::defer_lock);
// lock both unique_locks without deadlock
std::lock(lock1, lock2);
from.num_things -= num;
to.num_things += num;
// 'from.m' and 'to.m' mutexes unlocked in 'unique_lock' dtors
}
int main()
{
Box acc1(100);
Box acc2(50);
std::thread t1(transfer, std::ref(acc1), std::ref(acc2), 10);
std::thread t2(transfer, std::ref(acc2), std::ref(acc1), 5);
t1.join();
t2.join();
}
总结
所有 lock_guard 能够做到的事情,都可以使用 unique_lock 做到,反之则不然。
那么何时使用lock_guard呢?很简单,
需要使用锁的时候,首先考虑使用 lock_guard
它简单、明了、易读。如果用它完全ok,就不要考虑其他了。
如果现实不允许,就让实力派 unique_lock 出马吧!
