[英]Why does std::lock_guard release the lock after using std::adopt_lock?
In the following example, the method foo()
gets called, where it acquires ownership of a mutex, and locks it.在下面的例子中,方法
foo()
被调用,它获得一个互斥体的所有权,并锁定它。 It then calls check()
, which acquires ownership, but assumes that the mutex is already locked, and so simply adopts it using std::adopt_lock
.然后它调用
check()
,它获得所有权,但假定互斥锁已经被锁定,因此只需使用std::adopt_lock
采用它。
But when check()
finishes, the mutex gets unlocked.但是当
check()
完成时,互斥锁被解锁。 So when foo()
continues, the section I was trying to guard is actually no longer guarded.因此,当
foo()
继续时,我试图保护的部分实际上不再受到保护。
#include <mutex>
static std::mutex sessionLock;
bool check();
void foo() {
std::lock_guard<std::mutex> guard(sessionLock);
if (check()) {
// Do transaction
// Wait... the mutex is unlocked here!
}
}
bool check() {
std::lock_guard<std::mutex> guard(sessionLock, std::adopt_lock);
// Critical section
return true;
}
int main() {
foo();
return 0;
}
I find this behaviour very unintuitive.我发现这种行为非常不直观。 If a sub-method decides to take ownership of a lock using
std::adopt_lock
(ie. it doesn't call lock()
), shouldn't it also release ownership without calling unlock()
?如果子方法决定使用
std::adopt_lock
锁的所有权(即它不调用lock()
),它不应该在不调用unlock()
的情况下也释放所有权吗? The standard says otherwise, but I'm curious if this was an oversight or if there is a particular reason this is expected.标准另有规定,但我很好奇这是否是疏忽,或者是否有特定的原因是预期的。
This could be rewritten using std::recursive_mutex
, though in this case where a regular std::mutex
is used, is there a proper way inside check()
to ensure its critical section is guarded?这可以使用
std::recursive_mutex
重写,尽管在这种使用常规std::mutex
的情况下,在check()
中是否有适当的方法来确保其关键部分受到保护?
...though in this case where a regular
std::mutex
is used, is there a proper way insidecheck()
to ensure its critical section is guarded?...尽管在这种使用常规
std::mutex
的情况下,在check()
内部是否有适当的方法来确保其关键部分受到保护?
Yes.是的。 Use a
unique_lock<std::mutex>
in foo
instead of lock_guard
, and pass a const&
to that unique_lock
as an argument to check
so that it can validate the proper mutex is held:在
foo
中使用unique_lock<std::mutex>
而不是lock_guard
,并将const&
作为参数传递给该unique_lock
进行check
,以便它可以验证是否持有正确的互斥锁:
bool check(const std::unique_lock<std::mutex>& guard) {
assert(guard.owns_lock()); // guard holds *some* mutex...
assert(guard.mutex() == &sessionLock); // ...it is in fact sessionLock
// Critical section
return true;
}
void foo() {
std::unique_lock<std::mutex> guard(sessionLock);
if (check(guard)) {
// Do transaction - guard is still locked.
}
}
我知道这个问题已经过时了,但你也可以使用一个 std::recursive_mutex ,它允许同一个线程获取多级锁......所以每次它被锁定时,它都会增加一个新级别的层次所有权并解锁它会减少等级。:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.