shared_mutex 14 KB

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