shared_mutex 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. // -*- C++ -*-
  2. //===----------------------------------------------------------------------===//
  3. //
  4. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  5. // See https://llvm.org/LICENSE.txt for license information.
  6. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #ifndef _LIBCPP_SHARED_MUTEX
  10. #define _LIBCPP_SHARED_MUTEX
  11. /*
  12. shared_mutex synopsis
  13. // C++1y
  14. namespace std
  15. {
  16. class shared_mutex // C++17
  17. {
  18. public:
  19. shared_mutex();
  20. ~shared_mutex();
  21. shared_mutex(const shared_mutex&) = delete;
  22. shared_mutex& operator=(const shared_mutex&) = delete;
  23. // Exclusive ownership
  24. void lock(); // blocking
  25. bool try_lock();
  26. void unlock();
  27. // Shared ownership
  28. void lock_shared(); // blocking
  29. bool try_lock_shared();
  30. void unlock_shared();
  31. typedef implementation-defined native_handle_type; // See 30.2.3
  32. native_handle_type native_handle(); // See 30.2.3
  33. };
  34. class shared_timed_mutex
  35. {
  36. public:
  37. shared_timed_mutex();
  38. ~shared_timed_mutex();
  39. shared_timed_mutex(const shared_timed_mutex&) = delete;
  40. shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
  41. // Exclusive ownership
  42. void lock(); // blocking
  43. bool try_lock();
  44. template <class Rep, class Period>
  45. bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
  46. template <class Clock, class Duration>
  47. bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
  48. void unlock();
  49. // Shared ownership
  50. void lock_shared(); // blocking
  51. bool try_lock_shared();
  52. template <class Rep, class Period>
  53. bool
  54. try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
  55. template <class Clock, class Duration>
  56. bool
  57. try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
  58. void unlock_shared();
  59. };
  60. template <class Mutex>
  61. class shared_lock
  62. {
  63. public:
  64. typedef Mutex mutex_type;
  65. // Shared locking
  66. shared_lock() noexcept;
  67. explicit shared_lock(mutex_type& m); // blocking
  68. shared_lock(mutex_type& m, defer_lock_t) noexcept;
  69. shared_lock(mutex_type& m, try_to_lock_t);
  70. shared_lock(mutex_type& m, adopt_lock_t);
  71. template <class Clock, class Duration>
  72. shared_lock(mutex_type& m,
  73. const chrono::time_point<Clock, Duration>& abs_time);
  74. template <class Rep, class Period>
  75. shared_lock(mutex_type& m,
  76. const chrono::duration<Rep, Period>& rel_time);
  77. ~shared_lock();
  78. shared_lock(shared_lock const&) = delete;
  79. shared_lock& operator=(shared_lock const&) = delete;
  80. shared_lock(shared_lock&& u) noexcept;
  81. shared_lock& operator=(shared_lock&& u) noexcept;
  82. void lock(); // blocking
  83. bool try_lock();
  84. template <class Rep, class Period>
  85. bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
  86. template <class Clock, class Duration>
  87. bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
  88. void unlock();
  89. // Setters
  90. void swap(shared_lock& u) noexcept;
  91. mutex_type* release() noexcept;
  92. // Getters
  93. bool owns_lock() const noexcept;
  94. explicit operator bool () const noexcept;
  95. mutex_type* mutex() const noexcept;
  96. };
  97. template <class Mutex>
  98. void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
  99. } // std
  100. */
  101. #include <__assert> // all public C++ headers provide the assertion handler
  102. #include <__availability>
  103. #include <__config>
  104. #include <version>
  105. _LIBCPP_PUSH_MACROS
  106. #include <__undef_macros>
  107. #if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_LIBRARY)
  108. #include <__mutex_base>
  109. #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
  110. # pragma GCC system_header
  111. #endif
  112. #ifdef _LIBCPP_HAS_NO_THREADS
  113. # error "<shared_mutex> is not supported since libc++ has been configured without support for threads."
  114. #endif
  115. _LIBCPP_BEGIN_NAMESPACE_STD
  116. struct _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("shared_mutex"))
  117. __shared_mutex_base
  118. {
  119. mutex __mut_;
  120. condition_variable __gate1_;
  121. condition_variable __gate2_;
  122. unsigned __state_;
  123. static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
  124. static const unsigned __n_readers_ = ~__write_entered_;
  125. __shared_mutex_base();
  126. _LIBCPP_INLINE_VISIBILITY ~__shared_mutex_base() = default;
  127. __shared_mutex_base(const __shared_mutex_base&) = delete;
  128. __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
  129. // Exclusive ownership
  130. void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability()); // blocking
  131. bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
  132. void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
  133. // Shared ownership
  134. void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_shared_capability()); // blocking
  135. bool try_lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_shared_capability(true));
  136. void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_shared_capability());
  137. // typedef implementation-defined native_handle_type; // See 30.2.3
  138. // native_handle_type native_handle(); // See 30.2.3
  139. };
  140. #if _LIBCPP_STD_VER > 14
  141. class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_mutex
  142. {
  143. __shared_mutex_base __base_;
  144. public:
  145. _LIBCPP_INLINE_VISIBILITY shared_mutex() : __base_() {}
  146. _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default;
  147. shared_mutex(const shared_mutex&) = delete;
  148. shared_mutex& operator=(const shared_mutex&) = delete;
  149. // Exclusive ownership
  150. _LIBCPP_INLINE_VISIBILITY void lock() { return __base_.lock(); }
  151. _LIBCPP_INLINE_VISIBILITY bool try_lock() { return __base_.try_lock(); }
  152. _LIBCPP_INLINE_VISIBILITY void unlock() { return __base_.unlock(); }
  153. // Shared ownership
  154. _LIBCPP_INLINE_VISIBILITY void lock_shared() { return __base_.lock_shared(); }
  155. _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() { return __base_.try_lock_shared(); }
  156. _LIBCPP_INLINE_VISIBILITY void unlock_shared() { return __base_.unlock_shared(); }
  157. // typedef __shared_mutex_base::native_handle_type native_handle_type;
  158. // _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() { return __base::unlock_shared(); }
  159. };
  160. #endif
  161. class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_timed_mutex
  162. {
  163. __shared_mutex_base __base_;
  164. public:
  165. shared_timed_mutex();
  166. _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
  167. shared_timed_mutex(const shared_timed_mutex&) = delete;
  168. shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
  169. // Exclusive ownership
  170. void lock();
  171. bool try_lock();
  172. template <class _Rep, class _Period>
  173. _LIBCPP_INLINE_VISIBILITY
  174. bool
  175. try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
  176. {
  177. return try_lock_until(chrono::steady_clock::now() + __rel_time);
  178. }
  179. template <class _Clock, class _Duration>
  180. _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
  181. bool
  182. try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
  183. void unlock();
  184. // Shared ownership
  185. void lock_shared();
  186. bool try_lock_shared();
  187. template <class _Rep, class _Period>
  188. _LIBCPP_INLINE_VISIBILITY
  189. bool
  190. try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
  191. {
  192. return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
  193. }
  194. template <class _Clock, class _Duration>
  195. _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
  196. bool
  197. try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
  198. void unlock_shared();
  199. };
  200. template <class _Clock, class _Duration>
  201. bool
  202. shared_timed_mutex::try_lock_until(
  203. const chrono::time_point<_Clock, _Duration>& __abs_time)
  204. {
  205. unique_lock<mutex> __lk(__base_.__mut_);
  206. if (__base_.__state_ & __base_.__write_entered_)
  207. {
  208. while (true)
  209. {
  210. cv_status __status = __base_.__gate1_.wait_until(__lk, __abs_time);
  211. if ((__base_.__state_ & __base_.__write_entered_) == 0)
  212. break;
  213. if (__status == cv_status::timeout)
  214. return false;
  215. }
  216. }
  217. __base_.__state_ |= __base_.__write_entered_;
  218. if (__base_.__state_ & __base_.__n_readers_)
  219. {
  220. while (true)
  221. {
  222. cv_status __status = __base_.__gate2_.wait_until(__lk, __abs_time);
  223. if ((__base_.__state_ & __base_.__n_readers_) == 0)
  224. break;
  225. if (__status == cv_status::timeout)
  226. {
  227. __base_.__state_ &= ~__base_.__write_entered_;
  228. __base_.__gate1_.notify_all();
  229. return false;
  230. }
  231. }
  232. }
  233. return true;
  234. }
  235. template <class _Clock, class _Duration>
  236. bool
  237. shared_timed_mutex::try_lock_shared_until(
  238. const chrono::time_point<_Clock, _Duration>& __abs_time)
  239. {
  240. unique_lock<mutex> __lk(__base_.__mut_);
  241. if ((__base_.__state_ & __base_.__write_entered_) || (__base_.__state_ & __base_.__n_readers_) == __base_.__n_readers_)
  242. {
  243. while (true)
  244. {
  245. cv_status status = __base_.__gate1_.wait_until(__lk, __abs_time);
  246. if ((__base_.__state_ & __base_.__write_entered_) == 0 &&
  247. (__base_.__state_ & __base_.__n_readers_) < __base_.__n_readers_)
  248. break;
  249. if (status == cv_status::timeout)
  250. return false;
  251. }
  252. }
  253. unsigned __num_readers = (__base_.__state_ & __base_.__n_readers_) + 1;
  254. __base_.__state_ &= ~__base_.__n_readers_;
  255. __base_.__state_ |= __num_readers;
  256. return true;
  257. }
  258. template <class _Mutex>
  259. class shared_lock
  260. {
  261. public:
  262. typedef _Mutex mutex_type;
  263. private:
  264. mutex_type* __m_;
  265. bool __owns_;
  266. public:
  267. _LIBCPP_INLINE_VISIBILITY
  268. shared_lock() _NOEXCEPT
  269. : __m_(nullptr),
  270. __owns_(false)
  271. {}
  272. _LIBCPP_INLINE_VISIBILITY
  273. explicit shared_lock(mutex_type& __m)
  274. : __m_(_VSTD::addressof(__m)),
  275. __owns_(true)
  276. {__m_->lock_shared();}
  277. _LIBCPP_INLINE_VISIBILITY
  278. shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
  279. : __m_(_VSTD::addressof(__m)),
  280. __owns_(false)
  281. {}
  282. _LIBCPP_INLINE_VISIBILITY
  283. shared_lock(mutex_type& __m, try_to_lock_t)
  284. : __m_(_VSTD::addressof(__m)),
  285. __owns_(__m.try_lock_shared())
  286. {}
  287. _LIBCPP_INLINE_VISIBILITY
  288. shared_lock(mutex_type& __m, adopt_lock_t)
  289. : __m_(_VSTD::addressof(__m)),
  290. __owns_(true)
  291. {}
  292. template <class _Clock, class _Duration>
  293. _LIBCPP_INLINE_VISIBILITY
  294. shared_lock(mutex_type& __m,
  295. const chrono::time_point<_Clock, _Duration>& __abs_time)
  296. : __m_(_VSTD::addressof(__m)),
  297. __owns_(__m.try_lock_shared_until(__abs_time))
  298. {}
  299. template <class _Rep, class _Period>
  300. _LIBCPP_INLINE_VISIBILITY
  301. shared_lock(mutex_type& __m,
  302. const chrono::duration<_Rep, _Period>& __rel_time)
  303. : __m_(_VSTD::addressof(__m)),
  304. __owns_(__m.try_lock_shared_for(__rel_time))
  305. {}
  306. _LIBCPP_INLINE_VISIBILITY
  307. ~shared_lock()
  308. {
  309. if (__owns_)
  310. __m_->unlock_shared();
  311. }
  312. shared_lock(shared_lock const&) = delete;
  313. shared_lock& operator=(shared_lock const&) = delete;
  314. _LIBCPP_INLINE_VISIBILITY
  315. shared_lock(shared_lock&& __u) _NOEXCEPT
  316. : __m_(__u.__m_),
  317. __owns_(__u.__owns_)
  318. {
  319. __u.__m_ = nullptr;
  320. __u.__owns_ = false;
  321. }
  322. _LIBCPP_INLINE_VISIBILITY
  323. shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
  324. {
  325. if (__owns_)
  326. __m_->unlock_shared();
  327. __m_ = nullptr;
  328. __owns_ = false;
  329. __m_ = __u.__m_;
  330. __owns_ = __u.__owns_;
  331. __u.__m_ = nullptr;
  332. __u.__owns_ = false;
  333. return *this;
  334. }
  335. void lock();
  336. bool try_lock();
  337. template <class Rep, class Period>
  338. bool try_lock_for(const chrono::duration<Rep, Period>& __rel_time);
  339. template <class Clock, class Duration>
  340. bool try_lock_until(const chrono::time_point<Clock, Duration>& __abs_time);
  341. void unlock();
  342. // Setters
  343. _LIBCPP_INLINE_VISIBILITY
  344. void swap(shared_lock& __u) _NOEXCEPT
  345. {
  346. _VSTD::swap(__m_, __u.__m_);
  347. _VSTD::swap(__owns_, __u.__owns_);
  348. }
  349. _LIBCPP_INLINE_VISIBILITY
  350. mutex_type* release() _NOEXCEPT
  351. {
  352. mutex_type* __m = __m_;
  353. __m_ = nullptr;
  354. __owns_ = false;
  355. return __m;
  356. }
  357. // Getters
  358. _LIBCPP_INLINE_VISIBILITY
  359. bool owns_lock() const _NOEXCEPT {return __owns_;}
  360. _LIBCPP_INLINE_VISIBILITY
  361. explicit operator bool () const _NOEXCEPT {return __owns_;}
  362. _LIBCPP_INLINE_VISIBILITY
  363. mutex_type* mutex() const _NOEXCEPT {return __m_;}
  364. };
  365. _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(shared_lock);
  366. template <class _Mutex>
  367. void
  368. shared_lock<_Mutex>::lock()
  369. {
  370. if (__m_ == nullptr)
  371. __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
  372. if (__owns_)
  373. __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
  374. __m_->lock_shared();
  375. __owns_ = true;
  376. }
  377. template <class _Mutex>
  378. bool
  379. shared_lock<_Mutex>::try_lock()
  380. {
  381. if (__m_ == nullptr)
  382. __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
  383. if (__owns_)
  384. __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
  385. __owns_ = __m_->try_lock_shared();
  386. return __owns_;
  387. }
  388. template <class _Mutex>
  389. template <class _Rep, class _Period>
  390. bool
  391. shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
  392. {
  393. if (__m_ == nullptr)
  394. __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
  395. if (__owns_)
  396. __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
  397. __owns_ = __m_->try_lock_shared_for(__d);
  398. return __owns_;
  399. }
  400. template <class _Mutex>
  401. template <class _Clock, class _Duration>
  402. bool
  403. shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
  404. {
  405. if (__m_ == nullptr)
  406. __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
  407. if (__owns_)
  408. __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
  409. __owns_ = __m_->try_lock_shared_until(__t);
  410. return __owns_;
  411. }
  412. template <class _Mutex>
  413. void
  414. shared_lock<_Mutex>::unlock()
  415. {
  416. if (!__owns_)
  417. __throw_system_error(EPERM, "shared_lock::unlock: not locked");
  418. __m_->unlock_shared();
  419. __owns_ = false;
  420. }
  421. template <class _Mutex>
  422. inline _LIBCPP_INLINE_VISIBILITY
  423. void
  424. swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
  425. {__x.swap(__y);}
  426. _LIBCPP_END_NAMESPACE_STD
  427. #endif // _LIBCPP_STD_VER > 11
  428. _LIBCPP_POP_MACROS
  429. #endif // _LIBCPP_SHARED_MUTEX