简体   繁体   English

为什么 std::lock_guard 在使用 std::adopt_lock 后会释放锁?

[英]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 inside check() 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM