mutexlock.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. //
  6. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  7. // Use of this source code is governed by a BSD-style license that can be
  8. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  9. #pragma once
  10. #include <assert.h>
  11. #include <atomic>
  12. #include <mutex>
  13. #include <thread>
  14. #include "port/port.h"
  15. namespace ROCKSDB_NAMESPACE {
  16. // Helper class that locks a mutex on construction and unlocks the mutex when
  17. // the destructor of the MutexLock object is invoked.
  18. //
  19. // Typical usage:
  20. //
  21. // void MyClass::MyMethod() {
  22. // MutexLock l(&mu_); // mu_ is an instance variable
  23. // ... some complex code, possibly with multiple return paths ...
  24. // }
  25. class MutexLock {
  26. public:
  27. explicit MutexLock(port::Mutex *mu) : mu_(mu) {
  28. this->mu_->Lock();
  29. }
  30. // No copying allowed
  31. MutexLock(const MutexLock &) = delete;
  32. void operator=(const MutexLock &) = delete;
  33. ~MutexLock() { this->mu_->Unlock(); }
  34. private:
  35. port::Mutex *const mu_;
  36. };
  37. //
  38. // Acquire a ReadLock on the specified RWMutex.
  39. // The Lock will be automatically released then the
  40. // object goes out of scope.
  41. //
  42. class ReadLock {
  43. public:
  44. explicit ReadLock(port::RWMutex *mu) : mu_(mu) {
  45. this->mu_->ReadLock();
  46. }
  47. // No copying allowed
  48. ReadLock(const ReadLock &) = delete;
  49. void operator=(const ReadLock &) = delete;
  50. ~ReadLock() { this->mu_->ReadUnlock(); }
  51. private:
  52. port::RWMutex *const mu_;
  53. };
  54. //
  55. // Automatically unlock a locked mutex when the object is destroyed
  56. //
  57. class ReadUnlock {
  58. public:
  59. explicit ReadUnlock(port::RWMutex *mu) : mu_(mu) { mu->AssertHeld(); }
  60. // No copying allowed
  61. ReadUnlock(const ReadUnlock &) = delete;
  62. ReadUnlock &operator=(const ReadUnlock &) = delete;
  63. ~ReadUnlock() { mu_->ReadUnlock(); }
  64. private:
  65. port::RWMutex *const mu_;
  66. };
  67. //
  68. // Acquire a WriteLock on the specified RWMutex.
  69. // The Lock will be automatically released then the
  70. // object goes out of scope.
  71. //
  72. class WriteLock {
  73. public:
  74. explicit WriteLock(port::RWMutex *mu) : mu_(mu) {
  75. this->mu_->WriteLock();
  76. }
  77. // No copying allowed
  78. WriteLock(const WriteLock &) = delete;
  79. void operator=(const WriteLock &) = delete;
  80. ~WriteLock() { this->mu_->WriteUnlock(); }
  81. private:
  82. port::RWMutex *const mu_;
  83. };
  84. //
  85. // SpinMutex has very low overhead for low-contention cases. Method names
  86. // are chosen so you can use std::unique_lock or std::lock_guard with it.
  87. //
  88. class SpinMutex {
  89. public:
  90. SpinMutex() : locked_(false) {}
  91. bool try_lock() {
  92. auto currently_locked = locked_.load(std::memory_order_relaxed);
  93. return !currently_locked &&
  94. locked_.compare_exchange_weak(currently_locked, true,
  95. std::memory_order_acquire,
  96. std::memory_order_relaxed);
  97. }
  98. void lock() {
  99. for (size_t tries = 0;; ++tries) {
  100. if (try_lock()) {
  101. // success
  102. break;
  103. }
  104. port::AsmVolatilePause();
  105. if (tries > 100) {
  106. std::this_thread::yield();
  107. }
  108. }
  109. }
  110. void unlock() { locked_.store(false, std::memory_order_release); }
  111. private:
  112. std::atomic<bool> locked_;
  113. };
  114. } // namespace ROCKSDB_NAMESPACE