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

时间:2015-12-09 01:42:04

标签: c++ multithreading c++11

在下面的示例中,调用方法foo(),获取互斥锁的所有权并锁定它。然后调用check()来获取所有权,但假设互斥锁已被锁定,因此只需使用std::adopt_lock即可。

但是当check()完成时,互斥锁会被解锁。因此,当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;
}

我发现这种行为非常不直观。如果子方法决定使用std::adopt_lock获取锁的所有权(即它不会调用lock()),那么它是否也应该在不调用unlock()的情况下释放所有权?标准另有说法,但我很好奇这是否是一种疏忽,或者是否有特殊原因这是预期的。

这可以使用std::recursive_mutex重写,但在这种使用常规std::mutex的情况下,check()内是否有正确的方法来确保其关键部分受到保护?

1 个答案:

答案 0 :(得分:1)

  

...虽然在这种使用常规std::mutex的情况下,check()内是否有正确的方法来确保其关键部分受到保护?

是。在unique_lock<std::mutex>而不是foo中使用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.
  }
}