std::unique_lock
前面我们学习了 std::lock_guard,现在,我们介绍一种更灵活的 std::unique_lock,其参数可以有
- std::adopt_lock
- std::defer_lock 表示告诉 std::unique_lock 对象 locker 说这个锁并没有被锁住
考虑下面的例子:
可以看到,std::unique_lock 和 std::lock_guard 的功能是相似的。但 std::unique_lock 提供了更灵活的函数支持。
锁的粒度
通常用锁的粒度来描述一个锁所保护的数据量范围的大小。根据这个原则,可以分为 细粒度锁 和 粗粒度锁。
如果多个线程正在等待同一个资源,如果某个线程持有锁的时间太长,就会造成其他的线程一直等待。
例如:
等价于
在这种情况下,为了减少锁的持有时间以避免程序性能降低,我们需要在锁不再有必要持有的时候去选择性地释放它。这里,只有中间的 cout 部分会被 mutex 锁住,而 unlock 后面的 doWork 函数调用是没有被锁住的。
std::defer_lock 参数
std::defer_lock 表示告诉 std::unique_lock 对象 locker 说这个锁并没有被锁住。这样,doWork 的函数调用就是不加锁,不被保护的。
lock_guard 和 unique_lock 的异同
1)
都不能被赋值,但 unique_lock 可以移动,lock_guard 却不可以。
- unique_lock 实例发生移动时,相应的 mutex 所有权也将发生转移。
std::unique_lock<std::mutex> newlocker = std::move(oldlocker);
2)
unique_lock 提供了更灵活的方法,但却占用较多的空间,效率上会比 lock_guard 更慢一些。
如果 lock_guard 能够满足需求,建议还是使用 lock_guard。