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