本文翻译自:std::unique_lock or std::lock_guard?
I have two use cases. 我有两个用例。
A. I want to synchronise access by two threads to a queue. 答:我想通过两个线程同步对队列的访问。
B. I want to synchronise access by two threads to a queue and use a condition variable because one of the threads will wait on content to be stored into the queue by the other thread. B.我想同步两个线程对队列的访问并使用条件变量,因为其中一个线程将等待内容被另一个线程存储到队列中。
For use case AI see code example using std::lock_guard<>
. 对于用例AI,请参见使用std::lock_guard<>
代码示例。 For use case BI see code example using std::unique_lock<>
. 对于用例BI,请参见使用std::unique_lock<>
代码示例。
What is the difference between the two and which one should I use in which use case? 两者之间有什么区别?在哪种用例中应该使用哪一种?
#1楼
参考:https://stackoom.com/question/1O5Lh/std-unique-lock-std-mutex-或std-lock-guard-std-mutex
#2楼
Use lock_guard
unless you need to be able to manually unlock
the mutex in between without destroying the lock
. 除非需要能够在不破坏lock
情况下手动unlock
互斥锁,否则请使用lock_guard
。
In particular, condition_variable
unlocks its mutex when going to sleep upon calls to wait
. 特别是, condition_variable
在调用wait
进入睡眠状态时会解锁其互斥量。 That is why a lock_guard
is not sufficient here. 这就是为什么lock_guard
在这里不够的原因。
#3楼
The difference is that you can lock and unlock a std::unique_lock
. 区别在于您可以锁定和解锁std::unique_lock
。 std::lock_guard
will be locked only once on construction and unlocked on destruction. std::lock_guard
在构造时将仅被锁定一次,在破坏时将被解锁。
So for use case B you definitely need a std::unique_lock
for the condition variable. 因此,对于用例B,您肯定需要一个std::unique_lock
作为条件变量。 In case A it depends whether you need to relock the guard. 如果是A,则取决于是否需要重新锁定防护装置。
std::unique_lock
has other features that allow it to eg: be constructed without locking the mutex immediately but to build the RAII wrapper (see here ). std::unique_lock
具有其他功能,例如,可以在不立即锁定互斥体的情况下构造它,但可以构建RAII包装器(请参见此处 )。
std::lock_guard
also provides a convenient RAII wrapper, but cannot lock multiple mutexes safely. std::lock_guard
还提供了方便的RAII包装器,但不能安全地锁定多个互斥体。 It can be used when you need a wrapper for a limited scope, eg: a member function: 当需要有限范围的包装器时可以使用它,例如:成员函数:
class MyClass{std::mutex my_mutex;void member_foo() {std::lock_guard<mutex_type> lock(this->my_mutex); /*block of code which needs mutual exclusion (e.g. open the same file in multiple threads).*///mutex is automatically released when lock goes out of scope
};
To clarify a question by chmike, by default std::lock_guard
and std::unique_lock
are the same. 为了通过chmike澄清问题,默认情况下std::lock_guard
和std::unique_lock
相同。 So in the above case, you could replace std::lock_guard
with std::unique_lock
. 因此,在上述情况下,您可以将std::lock_guard
替换为std::unique_lock
。 However, std::unique_lock
might have a tad more overhead. 但是, std::unique_lock
可能会有更多开销。
Note that these days one should use std::scoped_lock
instead of std::lock_guard
. 请注意,这些天应该使用std::scoped_lock
而不是std::lock_guard
。
#4楼
lock_guard
and unique_lock
are pretty much the same thing; lock_guard
和unique_lock
几乎是同一件事; lock_guard
is a restricted version with a limited interface. lock_guard
是具有受限接口的受限版本。
A lock_guard
always holds a lock from its construction to its destruction. 从构造到破坏, lock_guard
始终保持着锁。 A unique_lock
can be created without immediately locking, can unlock at any point in its existence, and can transfer ownership of the lock from one instance to another. 可以在不立即锁定的情况下创建unique_lock
,可以在其存在的任何时候将其解锁,并且可以将锁的所有权从一个实例转移到另一个实例。
So you always use lock_guard
, unless you need the capabilities of unique_lock
. 因此,除非需要unique_lock
的功能,否则始终使用lock_guard
。 A condition_variable
needs a unique_lock
. condition_variable
需要unique_lock
。
#5楼
As has been mentioned by others, std::unique_lock tracks the locked status of the mutex, so you can defer locking until after construction of the lock, and unlock before destruction of the lock. 正如其他人提到的那样,std :: unique_lock跟踪互斥锁的锁定状态,因此您可以将锁定推迟到构造锁之后,再解锁直到销毁锁为止。 std::lock_guard does not permit this. std :: lock_guard不允许这样做。
There seems no reason why the std::condition_variable wait functions should not take a lock_guard as well as a unique_lock, because whenever a wait ends (for whatever reason) the mutex is automatically reacquired so that would not cause any semantic violation. 似乎没有理由为什么std :: condition_variable等待函数不应该同时使用lock_guard和unique_lock,因为只要等待结束(无论出于何种原因),都会自动重新获取互斥体,因此不会引起任何语义冲突。 However according to the standard, to use a std::lock_guard with a condition variable you have to use a std::condition_variable_any instead of std::condition_variable. 但是,根据标准,要将std :: lock_guard与条件变量一起使用,则必须使用std :: condition_variable_any而不是std :: condition_variable。
Edit : deleted "Using the pthreads interface std::condition_variable and std::condition_variable_any should be identical". 编辑 :删除了“使用pthreads接口std :: condition_variable和std :: condition_variable_any应该相同”。 On looking at gcc's implementation: 在查看gcc的实现时:
- std::condition_variable::wait(std::unique_lock&) just calls pthread_cond_wait() on the underlying pthread condition variable with respect to the mutex held by unique_lock (and so could equally do the same for lock_guard, but doesn't because the standard doesn't provide for that) std :: condition_variable :: wait(std :: unique_lock&)只是针对与unique_lock持有的互斥锁在底层pthread条件变量上调用pthread_cond_wait()(因此,对lock_guard可以同样执行此操作,但不是因为标准没有为此提供)
- std::condition_variable_any can work with any lockable object, including one which is not a mutex lock at all (it could therefore even work with an inter-process semaphore) std :: condition_variable_any可以与任何可锁定对象一起使用,包括根本不是互斥锁的对象(因此甚至可以与进程间信号灯一起使用)
#6楼
There are certain common things between lock_guard
and unique_lock
and certain differences. lock_guard
和unique_lock
之间有某些共同之处,也有一些区别。
But in the context of the question asked, the compiler does not allow using a lock_guard
in combination with a condition variable, because when a thread calls wait on a condition variable, the mutex gets unlocked automatically and when other thread/threads notify and the current thread is invoked (comes out of wait), the lock is re-acquired. 但是在提出问题的上下文中,编译器不允许将lock_guard
与条件变量结合使用,因为当线程调用等待条件变量时,互斥锁会自动解锁,而其他线程/线程通知当前线程被调用(退出等待状态),重新获得该锁。
This phenomenon is against the principle of lock_guard
. 这种现象违反了lock_guard
的原理。 lock_guard
can be constructed only once and destructed only once. lock_guard
只能构造一次,并且只能破坏一次。
Hence lock_guard
cannot be used in combination with a condition variable, but a unique_lock
can be (because unique_lock
can be locked and unlocked several times). 因此lock_guard
不能与条件变量组合使用,但一个unique_lock
即可(因为unique_lock
可以被锁定和解锁几次)。