shared_mutex revision 262801
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_mutex 23{ 24public: 25 shared_mutex(); 26 ~shared_mutex(); 27 28 shared_mutex(const shared_mutex&) = delete; 29 shared_mutex& operator=(const shared_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_LIBCPP_BEGIN_NAMESPACE_STD 116 117class _LIBCPP_TYPE_VIS shared_mutex 118{ 119 mutex __mut_; 120 condition_variable __gate1_; 121 condition_variable __gate2_; 122 unsigned __state_; 123 124 static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1); 125 static const unsigned __n_readers_ = ~__write_entered_; 126public: 127 shared_mutex(); 128 _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default; 129 130 shared_mutex(const shared_mutex&) = delete; 131 shared_mutex& operator=(const shared_mutex&) = delete; 132 133 // Exclusive ownership 134 void lock(); 135 bool try_lock(); 136 template <class _Rep, class _Period> 137 _LIBCPP_INLINE_VISIBILITY 138 bool 139 try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time) 140 { 141 return try_lock_until(chrono::steady_clock::now() + __rel_time); 142 } 143 template <class _Clock, class _Duration> 144 bool 145 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time); 146 void unlock(); 147 148 // Shared ownership 149 void lock_shared(); 150 bool try_lock_shared(); 151 template <class _Rep, class _Period> 152 _LIBCPP_INLINE_VISIBILITY 153 bool 154 try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time) 155 { 156 return try_lock_shared_until(chrono::steady_clock::now() + __rel_time); 157 } 158 template <class _Clock, class _Duration> 159 bool 160 try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time); 161 void unlock_shared(); 162}; 163 164template <class _Clock, class _Duration> 165bool 166shared_mutex::try_lock_until( 167 const chrono::time_point<_Clock, _Duration>& __abs_time) 168{ 169 unique_lock<mutex> __lk(__mut_); 170 if (__state_ & __write_entered_) 171 { 172 while (true) 173 { 174 cv_status __status = __gate1_.wait_until(__lk, __abs_time); 175 if ((__state_ & __write_entered_) == 0) 176 break; 177 if (__status == cv_status::timeout) 178 return false; 179 } 180 } 181 __state_ |= __write_entered_; 182 if (__state_ & __n_readers_) 183 { 184 while (true) 185 { 186 cv_status __status = __gate2_.wait_until(__lk, __abs_time); 187 if ((__state_ & __n_readers_) == 0) 188 break; 189 if (__status == cv_status::timeout) 190 { 191 __state_ &= ~__write_entered_; 192 return false; 193 } 194 } 195 } 196 return true; 197} 198 199template <class _Clock, class _Duration> 200bool 201shared_mutex::try_lock_shared_until( 202 const chrono::time_point<_Clock, _Duration>& __abs_time) 203{ 204 unique_lock<mutex> __lk(__mut_); 205 if ((__state_ & __write_entered_) || (__state_ & __n_readers_) == __n_readers_) 206 { 207 while (true) 208 { 209 cv_status status = __gate1_.wait_until(__lk, __abs_time); 210 if ((__state_ & __write_entered_) == 0 && 211 (__state_ & __n_readers_) < __n_readers_) 212 break; 213 if (status == cv_status::timeout) 214 return false; 215 } 216 } 217 unsigned __num_readers = (__state_ & __n_readers_) + 1; 218 __state_ &= ~__n_readers_; 219 __state_ |= __num_readers; 220 return true; 221} 222 223template <class _Mutex> 224class shared_lock 225{ 226public: 227 typedef _Mutex mutex_type; 228 229private: 230 mutex_type* __m_; 231 bool __owns_; 232 233public: 234 _LIBCPP_INLINE_VISIBILITY 235 shared_lock() noexcept 236 : __m_(nullptr), 237 __owns_(false) 238 {} 239 240 _LIBCPP_INLINE_VISIBILITY 241 explicit shared_lock(mutex_type& __m) 242 : __m_(&__m), 243 __owns_(true) 244 {__m_->lock_shared();} 245 246 _LIBCPP_INLINE_VISIBILITY 247 shared_lock(mutex_type& __m, defer_lock_t) noexcept 248 : __m_(&__m), 249 __owns_(false) 250 {} 251 252 _LIBCPP_INLINE_VISIBILITY 253 shared_lock(mutex_type& __m, try_to_lock_t) 254 : __m_(&__m), 255 __owns_(__m.try_lock_shared()) 256 {} 257 258 _LIBCPP_INLINE_VISIBILITY 259 shared_lock(mutex_type& __m, adopt_lock_t) 260 : __m_(&__m), 261 __owns_(true) 262 {} 263 264 template <class _Clock, class _Duration> 265 _LIBCPP_INLINE_VISIBILITY 266 shared_lock(mutex_type& __m, 267 const chrono::time_point<_Clock, _Duration>& __abs_time) 268 : __m_(&__m), 269 __owns_(__m.try_lock_shared_until(__abs_time)) 270 {} 271 272 template <class _Rep, class _Period> 273 _LIBCPP_INLINE_VISIBILITY 274 shared_lock(mutex_type& __m, 275 const chrono::duration<_Rep, _Period>& __rel_time) 276 : __m_(&__m), 277 __owns_(__m.try_lock_shared_for(__rel_time)) 278 {} 279 280 _LIBCPP_INLINE_VISIBILITY 281 ~shared_lock() 282 { 283 if (__owns_) 284 __m_->unlock_shared(); 285 } 286 287 shared_lock(shared_lock const&) = delete; 288 shared_lock& operator=(shared_lock const&) = delete; 289 290 _LIBCPP_INLINE_VISIBILITY 291 shared_lock(shared_lock&& __u) noexcept 292 : __m_(__u.__m_), 293 __owns_(__u.__owns_) 294 { 295 __u.__m_ = nullptr; 296 __u.__owns_ = false; 297 } 298 299 _LIBCPP_INLINE_VISIBILITY 300 shared_lock& operator=(shared_lock&& __u) noexcept 301 { 302 if (__owns_) 303 __m_->unlock_shared(); 304 __m_ = nullptr; 305 __owns_ = false; 306 __m_ = __u.__m_; 307 __owns_ = __u.__owns_; 308 __u.__m_ = nullptr; 309 __u.__owns_ = false; 310 return *this; 311 } 312 313 void lock(); 314 bool try_lock(); 315 template <class Rep, class Period> 316 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); 317 template <class Clock, class Duration> 318 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); 319 void unlock(); 320 321 // Setters 322 _LIBCPP_INLINE_VISIBILITY 323 void swap(shared_lock& __u) noexcept 324 { 325 _VSTD::swap(__m_, __u.__m_); 326 _VSTD::swap(__owns_, __u.__owns_); 327 } 328 329 _LIBCPP_INLINE_VISIBILITY 330 mutex_type* release() noexcept 331 { 332 mutex_type* __m = __m_; 333 __m_ = nullptr; 334 __owns_ = false; 335 return __m; 336 } 337 338 // Getters 339 _LIBCPP_INLINE_VISIBILITY 340 bool owns_lock() const noexcept {return __owns_;} 341 342 _LIBCPP_INLINE_VISIBILITY 343 explicit operator bool () const noexcept {return __owns_;} 344 345 _LIBCPP_INLINE_VISIBILITY 346 mutex_type* mutex() const noexcept {return __m_;} 347}; 348 349template <class _Mutex> 350void 351shared_lock<_Mutex>::lock() 352{ 353 if (__m_ == nullptr) 354 __throw_system_error(EPERM, "shared_lock::lock: references null mutex"); 355 if (__owns_) 356 __throw_system_error(EDEADLK, "shared_lock::lock: already locked"); 357 __m_->lock_shared(); 358 __owns_ = true; 359} 360 361template <class _Mutex> 362bool 363shared_lock<_Mutex>::try_lock() 364{ 365 if (__m_ == nullptr) 366 __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex"); 367 if (__owns_) 368 __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked"); 369 __owns_ = __m_->try_lock_shared(); 370 return __owns_; 371} 372 373template <class _Mutex> 374template <class _Rep, class _Period> 375bool 376shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d) 377{ 378 if (__m_ == nullptr) 379 __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex"); 380 if (__owns_) 381 __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked"); 382 __owns_ = __m_->try_lock_shared_for(__d); 383 return __owns_; 384} 385 386template <class _Mutex> 387template <class _Clock, class _Duration> 388bool 389shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) 390{ 391 if (__m_ == nullptr) 392 __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex"); 393 if (__owns_) 394 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked"); 395 __owns_ = __m_->try_lock_shared_until(__t); 396 return __owns_; 397} 398 399template <class _Mutex> 400void 401shared_lock<_Mutex>::unlock() 402{ 403 if (!__owns_) 404 __throw_system_error(EPERM, "shared_lock::unlock: not locked"); 405 __m_->unlock_shared(); 406 __owns_ = false; 407} 408 409template <class _Mutex> 410inline _LIBCPP_INLINE_VISIBILITY 411void 412swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) noexcept 413 {__x.swap(__y);} 414 415_LIBCPP_END_NAMESPACE_STD 416 417#endif // _LIBCPP_STD_VER > 11 418 419#endif // _LIBCPP_SHARED_MUTEX 420