shared_mutex.hpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * Copyright (c) 2017-2023 zhllxt
  3. *
  4. * author : zhllxt
  5. * email : 37792738@qq.com
  6. *
  7. * Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. */
  10. #ifndef __ASIO2_SHARED_MTX_HPP__
  11. #define __ASIO2_SHARED_MTX_HPP__
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. #pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <mutex>
  16. #include <shared_mutex>
  17. // https://clang.llvm.org/docs/ThreadSafetyAnalysis.html
  18. // https://stackoverflow.com/questions/33608378/clang-thread-safety-annotation-and-shared-capabilities
  19. // when compiled with "Visual Studio 2017 - Windows XP (v141_xp)"
  20. // there is hasn't shared_mutex
  21. #ifndef ASIO2_HAS_SHARED_MUTEX
  22. #if defined(_MSC_VER)
  23. #if defined(_HAS_SHARED_MUTEX)
  24. #if _HAS_SHARED_MUTEX
  25. #define ASIO2_HAS_SHARED_MUTEX 1
  26. #define asio2_shared_mutex std::shared_mutex
  27. #define asio2_shared_lock std::shared_lock
  28. #define asio2_unique_lock std::unique_lock
  29. #else
  30. #define ASIO2_HAS_SHARED_MUTEX 0
  31. #define asio2_shared_mutex std::mutex
  32. #define asio2_shared_lock std::lock_guard
  33. #define asio2_unique_lock std::lock_guard
  34. #endif
  35. #else
  36. #define ASIO2_HAS_SHARED_MUTEX 1
  37. #define asio2_shared_mutex std::shared_mutex
  38. #define asio2_shared_lock std::shared_lock
  39. #define asio2_unique_lock std::unique_lock
  40. #endif
  41. #else
  42. #define ASIO2_HAS_SHARED_MUTEX 1
  43. #define asio2_shared_mutex std::shared_mutex
  44. #define asio2_shared_lock std::shared_lock
  45. #define asio2_unique_lock std::unique_lock
  46. #endif
  47. #endif
  48. // Enable thread safety attributes only with clang.
  49. // The attributes can be safely erased when compiling with other compilers.
  50. #if defined(__clang__) && (!defined(SWIG))
  51. #define ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
  52. #else
  53. #define ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
  54. #endif
  55. #define ASIO2_CAPABILITY(x) \
  56. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
  57. #define ASIO2_SCOPED_CAPABILITY \
  58. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
  59. #define ASIO2_GUARDED_BY(x) \
  60. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
  61. #define ASIO2_PT_GUARDED_BY(x) \
  62. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
  63. #define ASIO2_ACQUIRED_BEFORE(...) \
  64. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
  65. #define ASIO2_ACQUIRED_AFTER(...) \
  66. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
  67. #define ASIO2_REQUIRES(...) \
  68. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
  69. #define ASIO2_REQUIRES_SHARED(...) \
  70. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
  71. #define ASIO2_ACQUIRE(...) \
  72. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
  73. #define ASIO2_ACQUIRE_SHARED(...) \
  74. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
  75. #define ASIO2_RELEASE(...) \
  76. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
  77. #define ASIO2_RELEASE_SHARED(...) \
  78. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
  79. #define ASIO2_RELEASE_GENERIC(...) \
  80. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(release_generic_capability(__VA_ARGS__))
  81. #define ASIO2_TRY_ACQUIRE(...) \
  82. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
  83. #define ASIO2_TRY_ACQUIRE_SHARED(...) \
  84. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
  85. #define ASIO2_EXCLUDES(...) \
  86. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
  87. #define ASIO2_ASSERT_CAPABILITY(x) \
  88. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
  89. #define ASIO2_ASSERT_SHARED_CAPABILITY(x) \
  90. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
  91. #define ASIO2_RETURN_CAPABILITY(x) \
  92. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
  93. #define ASIO2_NO_THREAD_SAFETY_ANALYSIS \
  94. ASIO2_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
  95. namespace asio2
  96. {
  97. // Defines an annotated interface for mutexes.
  98. // These methods can be implemented to use any internal mutex implementation.
  99. class ASIO2_CAPABILITY("mutex") shared_mutexer
  100. {
  101. public:
  102. inline asio2_shared_mutex& native_handle() { return mutex_; }
  103. // Good software engineering practice dictates that mutexes should be private members,
  104. // because the locking mechanism used by a thread-safe class is part of its internal
  105. // implementation. However, private mutexes can sometimes leak into the public interface
  106. // of a class. Thread safety attributes follow normal C++ access restrictions, so if is
  107. // a private member of , then it is an error to write in an attribute.mucc.mu
  108. private:
  109. mutable asio2_shared_mutex mutex_;
  110. };
  111. // shared_locker is an RAII class that acquires a mutex in its constructor, and
  112. // releases it in its destructor.
  113. class ASIO2_SCOPED_CAPABILITY shared_locker
  114. {
  115. public:
  116. // Acquire mutex in shared mode, implicitly acquire *this and associate it with mutex.
  117. explicit shared_locker(shared_mutexer& m) ASIO2_ACQUIRE_SHARED(m) : lock_(m.native_handle()) {}
  118. // Release *this and all associated mutexes, if they are still held.
  119. // There is no warning if the scope was already unlocked before.
  120. // Note: can't use ASIO2_RELEASE_SHARED
  121. // @see: https://stackoverflow.com/questions/33608378/clang-thread-safety-annotation-and-shared-capabilities
  122. ~shared_locker() ASIO2_RELEASE()
  123. {
  124. }
  125. private:
  126. asio2_shared_lock<asio2_shared_mutex> lock_;
  127. };
  128. // unique_locker is an RAII class that acquires a mutex in its constructor, and
  129. // releases it in its destructor.
  130. class ASIO2_SCOPED_CAPABILITY unique_locker
  131. {
  132. public:
  133. // Acquire mutex, implicitly acquire *this and associate it with mutex.
  134. explicit unique_locker(shared_mutexer& m) ASIO2_ACQUIRE(m) : lock_(m.native_handle()) {}
  135. // Release *this and all associated mutexes, if they are still held.
  136. // There is no warning if the scope was already unlocked before.
  137. ~unique_locker() ASIO2_RELEASE()
  138. {
  139. }
  140. private:
  141. asio2_unique_lock<asio2_shared_mutex> lock_;
  142. };
  143. }
  144. #endif // !__ASIO2_SHARED_MTX_HPP__