boost::unique_lock vs boost::lock_guard

boost::unique_lock vs boost::lock_guard

本文关键字:lock boost guard vs unique      更新时间:2023-10-16

我不太明白这两个锁类之间的区别。在boost文档中说,boost::unique_lock不自动实现锁。

这是否意味着unique_locklock_guard之间的主要区别在于unique_lock必须显式调用lock()函数?

首先回答你的问题。不,你不需要在unique_lock上调用lock。

unique_lock只是一个具有更多特性的锁类。在大多数情况下,lock_guard会做你想做的,并且是足够的。
unique_lock还提供了更多的特性。例如,如果你需要一个超时,或者如果你想把你的锁推迟到一个比对象构造更晚的点,一个定时等待。所以这很大程度上取决于你想做什么。顺便说一句:下面的代码片段做同样的事情。

boost::mutex mutex;
boost::lock_guard<boost::mutex> lock(mutex);

boost::mutex mutex;
boost::unique_lock<boost::mutex> lock(mutex);

第一个可以用来同步对数据的访问,但是如果你想使用条件变量,你需要使用第二个。

目前最好的投票答案是好的,但它并没有澄清我的疑问,直到我深入挖掘了一点,所以决定与可能在同一条船的人分享。

首先,lock_guardunique_lock都遵循RAII模式,在最简单的用例中,锁在构造期间获得,在销毁期间自动解锁。如果这是你的用例,那么你不需要unique_lock的额外灵活性,lock_guard将更有效。

两者之间的关键区别是unique_lock实例不需要总是拥有与之关联的互斥锁,而在lock_guard中它拥有互斥锁。这意味着unique_lock需要有一个额外的标志来指示它是否拥有锁和另一个额外的方法'owns_lock()'来检查。知道了这一点,我们就可以解释这个标志带来的所有额外的好处,以及要设置和检查的额外数据的开销

  1. 锁不必在构造时立即采取,您可以在构造期间传递标志std::defer_lock以保持互斥锁在构造期间解锁。
  2. 我们可以在函数结束之前解锁它,而不必等待析构函数释放它,这很方便。你可以从一个函数传递锁的所有权,它是可移动而不是可复制
  3. 它可以与条件变量一起使用,因为这需要在等待条件时锁定互斥锁,检查条件并解锁。

它们的实现可以在path…/boost/thread/locks.hpp下找到-它们只是一个挨着另一个坐着:)总之:

lock_guard是一个简短的实用程序类,在构造函数中锁定互斥锁,在析构函数中解锁,不关心细节。

unique_lock稍微复杂一点,增加了相当多的特性——但它仍然在构造函数中自动锁定。之所以叫unique_lock,是因为它引入了"锁所有权"的概念(参见owns_lock()方法)。

如果你已经习惯了pthreads(3):

  • boost::mutex = pthread_mutex_*
  • boost::unique_lock = pthread_rwlock_*用于获取写/排他锁(即pthread_rwlock_wrlock)
  • boost::shared_lock = pthread_rwlock_*用于获取读/共享锁(即pthread_rwlock_rdlock)

是的,boost::unique_lockboost::mutex函数的方式相似,但boost::mutex通常是一个更轻的互斥锁来获取和释放。也就是说,已经获得锁的shared_lock更快(并且允许并发),但是获得unique_lock的成本相对较高。

您必须深入了解实现细节,但这是预期差异的要点。


说到性能,这里有一个比较有用的延迟:

http://www.eecs.berkeley.edu/%7Ercs/research/interactive_latency.html

如果我/某人可以对不同pthread_*原语的相对成本进行基准测试就好了,但是最后我看,pthread_mutex_*是~25us,而pthread_rwlock_*是~20-100us,这取决于读锁是否已经获得(~10us)或是否(~20us)或写(~100us)。你必须通过基准测试来确认当前的数字,我相信这是非常特定于操作系统的。

我认为当您需要强调唯一锁和共享锁之间的区别时,也可以使用unique_lock