C++ std::unique_lock<std::mutex> 还是 std::lock_guard<std::mutex> ?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20516773/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
std::unique_lock<std::mutex> or std::lock_guard<std::mutex>?
提问by chmike
I have two use cases.
我有两个用例。
A. I want to synchronise access by two threads to a queue.
A. 我想同步两个线程对一个队列的访问。
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 A I see code example using std::lock_guard<>
. For use case B I see code example using std::unique_lock<>
.
对于用例 AI,请参阅使用std::lock_guard<>
. 对于用例 BI,请参阅使用std::unique_lock<>
.
What is the difference between the two and which one should I use in which use case?
两者之间有什么区别,我应该在哪个用例中使用哪个?
采纳答案by Stephan Dollberg
The difference is that you can lock and unlock a std::unique_lock
. std::lock_guard
will be locked only once on construction and unlocked on destruction.
不同之处在于您可以锁定和解锁std::unique_lock
. std::lock_guard
只会在建造时锁定一次,在销毁时解锁。
So for use case B you definitely need a std::unique_lock
for the condition variable. In case A it depends whether you need to relock the guard.
因此,对于用例 B,您肯定需要 astd::unique_lock
作为条件变量。在 A 情况下,这取决于您是否需要重新锁定警卫。
std::unique_lock
has other features that allow it to e.g.: 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. It can be used when you need a wrapper for a limited scope, e.g.: a member function:
std::lock_guard
还提供了一个方便的 RAII 包装器,但不能安全地锁定多个互斥锁。当您需要有限范围的包装器时可以使用它,例如:成员函数:
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.
So in the above case, you could replace std::lock_guard
with std::unique_lock
. However, std::unique_lock
might have a tad more overhead.
通过chmike澄清一个问题,默认情况下std::lock_guard
和std::unique_lock
是一样的。因此,在上述情况下,您可以替换std::lock_guard
为std::unique_lock
. 但是,std::unique_lock
可能会有更多的开销。
Note that these days one should use std::scoped_lock
instead of std::lock_guard
.
请注意,现在应该使用std::scoped_lock
而不是std::lock_guard
.
回答by Sebastian Redl
lock_guard
and unique_lock
are pretty much the same thing; lock_guard
is a restricted version with a limited interface.
lock_guard
并且unique_lock
几乎是一样的;lock_guard
是一个界面受限的受限版本。
A lock_guard
always holds a lock from its construction to its destruction. 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.
Alock_guard
从构造到销毁始终持有锁。Aunique_lock
可以在不立即锁定的情况下创建,可以在其存在的任何时候解锁,并且可以将锁的所有权从一个实例转移到另一个实例。
So you always use lock_guard
, unless you need the capabilities of unique_lock
. A condition_variable
needs a unique_lock
.
所以你总是使用lock_guard
,除非你需要unique_lock
. Acondition_variable
需要一个unique_lock
.
回答by ComicSansMS
Use lock_guard
unless you need to be able to manually unlock
the mutex in between without destroying the lock
.
使用lock_guard
,除非你需要能够手动unlock
互斥之间不破坏lock
。
In particular, condition_variable
unlocks its mutex when going to sleep upon calls to wait
. That is why a lock_guard
is not sufficient here.
特别是,condition_variable
在调用wait
. 这就是为什么 alock_guard
在这里是不够的。
回答by Sandeep
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.
但是在所问问题的上下文中,编译器不允许将 alock_guard
与条件变量结合使用,因为当线程调用条件变量上的等待时,互斥锁会自动解锁,并且当其他线程/线程通知和当前线程时被调用(退出等待),重新获取锁。
This phenomenon is against the principle of lock_guard
. lock_guard
can be constructed only once and destructed only once.
这种现象是违反原则的lock_guard
。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
不能与条件变量结合使用,但 aunique_lock
可以(因为unique_lock
可以多次锁定和解锁)。
回答by rekkalmd
They are not really same mutexes, lock_guard<muType>
has nearly the same as std::mutex
, with a difference that it's lifetime ends at the end of the scope (D-tor called) so a clear definition about these two mutexes :
它们并不是真正相同的互斥锁,lock_guard<muType>
几乎与 相同std::mutex
,不同之处在于它的生命周期在范围的末尾(D-tor 调用)结束,因此对这两个互斥锁有明确的定义:
lock_guard<muType>
has a mechanism for owning a mutex for the duration of a scoped block.
lock_guard<muType>
具有在作用域块的持续时间内拥有互斥锁的机制。
And
和
unique_lock<muType>
is a wrapper allowing deferred locking, time-constrained attempts at locking, recursive locking, transfer of lock ownership, and use with condition variables.
unique_lock<muType>
是一个包装器,允许延迟锁定、有时间限制的锁定尝试、递归锁定、锁定所有权的转移以及与条件变量一起使用。
Here is an example implemetation :
这是一个示例实现:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <chrono>
using namespace std::chrono;
class Product{
public:
Product(int data):mdata(data){
}
virtual~Product(){
}
bool isReady(){
return flag;
}
void showData(){
std::cout<<mdata<<std::endl;
}
void read(){
std::this_thread::sleep_for(milliseconds(2000));
std::lock_guard<std::mutex> guard(mmutex);
flag = true;
std::cout<<"Data is ready"<<std::endl;
cvar.notify_one();
}
void task(){
std::unique_lock<std::mutex> lock(mmutex);
cvar.wait(lock, [&, this]() mutable throw() -> bool{ return this->isReady(); });
mdata+=1;
}
protected:
std::condition_variable cvar;
std::mutex mmutex;
int mdata;
bool flag = false;
};
int main(){
int a = 0;
Product product(a);
std::thread reading(product.read, &product);
std::thread setting(product.task, &product);
reading.join();
setting.join();
product.showData();
return 0;
}
In this example, i used the unique_lock<muType>
with condition variable
在这个例子中,我使用了unique_lock<muType>
withcondition variable
回答by Chris Vine
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::lock_guard does not permit this.
正如其他人提到的, std::unique_lock 跟踪互斥锁的锁定状态,因此您可以将锁定推迟到锁构造之后,并在锁销毁之前解锁。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. 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::condition_variable 等待函数不应该采用 lock_guard 和 unique_lock,因为每当等待结束(无论出于何种原因)互斥量都会自动重新获取,这样就不会导致任何语义违规。但是,根据标准,要将 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". On looking at gcc's implementation:
编辑:删除“使用 pthreads 接口 std::condition_variable 和 std::condition_variable_any 应该是相同的”。在查看 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_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::wait(std::unique_lock&) 只是在底层 pthread 条件变量上调用关于 unique_lock 持有的互斥锁的 pthread_cond_wait() (因此同样可以对 lock_guard 做同样的事情,但不是因为标准没有提供)
- std::condition_variable_any 可以与任何可锁定对象一起工作,包括一个根本不是互斥锁的对象(因此它甚至可以与进程间信号量一起工作)