libstdc++
|
00001 // <mutex> -*- C++ -*- 00002 00003 // Copyright (C) 2003-2016 Free Software Foundation, Inc. 00004 // 00005 // This file is part of the GNU ISO C++ Library. This library is free 00006 // software; you can redistribute it and/or modify it under the 00007 // terms of the GNU General Public License as published by the 00008 // Free Software Foundation; either version 3, or (at your option) 00009 // any later version. 00010 00011 // This library is distributed in the hope that it will be useful, 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 // GNU General Public License for more details. 00015 00016 // Under Section 7 of GPL version 3, you are granted additional 00017 // permissions described in the GCC Runtime Library Exception, version 00018 // 3.1, as published by the Free Software Foundation. 00019 00020 // You should have received a copy of the GNU General Public License and 00021 // a copy of the GCC Runtime Library Exception along with this program; 00022 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 00023 // <http://www.gnu.org/licenses/>. 00024 00025 /** @file include/mutex 00026 * This is a Standard C++ Library header. 00027 */ 00028 00029 #ifndef _GLIBCXX_MUTEX 00030 #define _GLIBCXX_MUTEX 1 00031 00032 #pragma GCC system_header 00033 00034 #if __cplusplus < 201103L 00035 # include <bits/c++0x_warning.h> 00036 #else 00037 00038 #include <tuple> 00039 #include <chrono> 00040 #include <exception> 00041 #include <type_traits> 00042 #include <functional> 00043 #include <system_error> 00044 #include <bits/std_mutex.h> 00045 #if ! _GTHREAD_USE_MUTEX_TIMEDLOCK 00046 # include <condition_variable> 00047 # include <thread> 00048 #endif 00049 00050 #ifdef _GLIBCXX_USE_C99_STDINT_TR1 00051 00052 namespace std _GLIBCXX_VISIBILITY(default) 00053 { 00054 _GLIBCXX_BEGIN_NAMESPACE_VERSION 00055 00056 /** 00057 * @ingroup mutexes 00058 * @{ 00059 */ 00060 00061 #ifdef _GLIBCXX_HAS_GTHREADS 00062 00063 // Common base class for std::recursive_mutex and std::recursive_timed_mutex 00064 class __recursive_mutex_base 00065 { 00066 protected: 00067 typedef __gthread_recursive_mutex_t __native_type; 00068 00069 __recursive_mutex_base(const __recursive_mutex_base&) = delete; 00070 __recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete; 00071 00072 #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT 00073 __native_type _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT; 00074 00075 __recursive_mutex_base() = default; 00076 #else 00077 __native_type _M_mutex; 00078 00079 __recursive_mutex_base() 00080 { 00081 // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may) 00082 __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); 00083 } 00084 00085 ~__recursive_mutex_base() 00086 { __gthread_recursive_mutex_destroy(&_M_mutex); } 00087 #endif 00088 }; 00089 00090 /// The standard recursive mutex type. 00091 class recursive_mutex : private __recursive_mutex_base 00092 { 00093 public: 00094 typedef __native_type* native_handle_type; 00095 00096 recursive_mutex() = default; 00097 ~recursive_mutex() = default; 00098 00099 recursive_mutex(const recursive_mutex&) = delete; 00100 recursive_mutex& operator=(const recursive_mutex&) = delete; 00101 00102 void 00103 lock() 00104 { 00105 int __e = __gthread_recursive_mutex_lock(&_M_mutex); 00106 00107 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 00108 if (__e) 00109 __throw_system_error(__e); 00110 } 00111 00112 bool 00113 try_lock() noexcept 00114 { 00115 // XXX EINVAL, EAGAIN, EBUSY 00116 return !__gthread_recursive_mutex_trylock(&_M_mutex); 00117 } 00118 00119 void 00120 unlock() 00121 { 00122 // XXX EINVAL, EAGAIN, EBUSY 00123 __gthread_recursive_mutex_unlock(&_M_mutex); 00124 } 00125 00126 native_handle_type 00127 native_handle() 00128 { return &_M_mutex; } 00129 }; 00130 00131 #if _GTHREAD_USE_MUTEX_TIMEDLOCK 00132 template<typename _Derived> 00133 class __timed_mutex_impl 00134 { 00135 protected: 00136 typedef chrono::high_resolution_clock __clock_t; 00137 00138 template<typename _Rep, typename _Period> 00139 bool 00140 _M_try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 00141 { 00142 using chrono::steady_clock; 00143 auto __rt = chrono::duration_cast<steady_clock::duration>(__rtime); 00144 if (ratio_greater<steady_clock::period, _Period>()) 00145 ++__rt; 00146 return _M_try_lock_until(steady_clock::now() + __rt); 00147 } 00148 00149 template<typename _Duration> 00150 bool 00151 _M_try_lock_until(const chrono::time_point<__clock_t, 00152 _Duration>& __atime) 00153 { 00154 auto __s = chrono::time_point_cast<chrono::seconds>(__atime); 00155 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 00156 00157 __gthread_time_t __ts = { 00158 static_cast<std::time_t>(__s.time_since_epoch().count()), 00159 static_cast<long>(__ns.count()) 00160 }; 00161 00162 return static_cast<_Derived*>(this)->_M_timedlock(__ts); 00163 } 00164 00165 template<typename _Clock, typename _Duration> 00166 bool 00167 _M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 00168 { 00169 auto __rtime = __atime - _Clock::now(); 00170 return _M_try_lock_until(__clock_t::now() + __rtime); 00171 } 00172 }; 00173 00174 /// The standard timed mutex type. 00175 class timed_mutex 00176 : private __mutex_base, public __timed_mutex_impl<timed_mutex> 00177 { 00178 public: 00179 typedef __native_type* native_handle_type; 00180 00181 timed_mutex() = default; 00182 ~timed_mutex() = default; 00183 00184 timed_mutex(const timed_mutex&) = delete; 00185 timed_mutex& operator=(const timed_mutex&) = delete; 00186 00187 void 00188 lock() 00189 { 00190 int __e = __gthread_mutex_lock(&_M_mutex); 00191 00192 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 00193 if (__e) 00194 __throw_system_error(__e); 00195 } 00196 00197 bool 00198 try_lock() noexcept 00199 { 00200 // XXX EINVAL, EAGAIN, EBUSY 00201 return !__gthread_mutex_trylock(&_M_mutex); 00202 } 00203 00204 template <class _Rep, class _Period> 00205 bool 00206 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 00207 { return _M_try_lock_for(__rtime); } 00208 00209 template <class _Clock, class _Duration> 00210 bool 00211 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 00212 { return _M_try_lock_until(__atime); } 00213 00214 void 00215 unlock() 00216 { 00217 // XXX EINVAL, EAGAIN, EBUSY 00218 __gthread_mutex_unlock(&_M_mutex); 00219 } 00220 00221 native_handle_type 00222 native_handle() 00223 { return &_M_mutex; } 00224 00225 private: 00226 friend class __timed_mutex_impl<timed_mutex>; 00227 00228 bool 00229 _M_timedlock(const __gthread_time_t& __ts) 00230 { return !__gthread_mutex_timedlock(&_M_mutex, &__ts); } 00231 }; 00232 00233 /// recursive_timed_mutex 00234 class recursive_timed_mutex 00235 : private __recursive_mutex_base, 00236 public __timed_mutex_impl<recursive_timed_mutex> 00237 { 00238 public: 00239 typedef __native_type* native_handle_type; 00240 00241 recursive_timed_mutex() = default; 00242 ~recursive_timed_mutex() = default; 00243 00244 recursive_timed_mutex(const recursive_timed_mutex&) = delete; 00245 recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; 00246 00247 void 00248 lock() 00249 { 00250 int __e = __gthread_recursive_mutex_lock(&_M_mutex); 00251 00252 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 00253 if (__e) 00254 __throw_system_error(__e); 00255 } 00256 00257 bool 00258 try_lock() noexcept 00259 { 00260 // XXX EINVAL, EAGAIN, EBUSY 00261 return !__gthread_recursive_mutex_trylock(&_M_mutex); 00262 } 00263 00264 template <class _Rep, class _Period> 00265 bool 00266 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 00267 { return _M_try_lock_for(__rtime); } 00268 00269 template <class _Clock, class _Duration> 00270 bool 00271 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 00272 { return _M_try_lock_until(__atime); } 00273 00274 void 00275 unlock() 00276 { 00277 // XXX EINVAL, EAGAIN, EBUSY 00278 __gthread_recursive_mutex_unlock(&_M_mutex); 00279 } 00280 00281 native_handle_type 00282 native_handle() 00283 { return &_M_mutex; } 00284 00285 private: 00286 friend class __timed_mutex_impl<recursive_timed_mutex>; 00287 00288 bool 00289 _M_timedlock(const __gthread_time_t& __ts) 00290 { return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts); } 00291 }; 00292 00293 #else // !_GTHREAD_USE_MUTEX_TIMEDLOCK 00294 00295 /// timed_mutex 00296 class timed_mutex 00297 { 00298 mutex _M_mut; 00299 condition_variable _M_cv; 00300 bool _M_locked = false; 00301 00302 public: 00303 00304 timed_mutex() = default; 00305 ~timed_mutex() { __glibcxx_assert( !_M_locked ); } 00306 00307 timed_mutex(const timed_mutex&) = delete; 00308 timed_mutex& operator=(const timed_mutex&) = delete; 00309 00310 void 00311 lock() 00312 { 00313 unique_lock<mutex> __lk(_M_mut); 00314 _M_cv.wait(__lk, [&]{ return !_M_locked; }); 00315 _M_locked = true; 00316 } 00317 00318 bool 00319 try_lock() 00320 { 00321 lock_guard<mutex> __lk(_M_mut); 00322 if (_M_locked) 00323 return false; 00324 _M_locked = true; 00325 return true; 00326 } 00327 00328 template<typename _Rep, typename _Period> 00329 bool 00330 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 00331 { 00332 unique_lock<mutex> __lk(_M_mut); 00333 if (!_M_cv.wait_for(__lk, __rtime, [&]{ return !_M_locked; })) 00334 return false; 00335 _M_locked = true; 00336 return true; 00337 } 00338 00339 template<typename _Clock, typename _Duration> 00340 bool 00341 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 00342 { 00343 unique_lock<mutex> __lk(_M_mut); 00344 if (!_M_cv.wait_until(__lk, __atime, [&]{ return !_M_locked; })) 00345 return false; 00346 _M_locked = true; 00347 return true; 00348 } 00349 00350 void 00351 unlock() 00352 { 00353 lock_guard<mutex> __lk(_M_mut); 00354 __glibcxx_assert( _M_locked ); 00355 _M_locked = false; 00356 _M_cv.notify_one(); 00357 } 00358 }; 00359 00360 /// recursive_timed_mutex 00361 class recursive_timed_mutex 00362 { 00363 mutex _M_mut; 00364 condition_variable _M_cv; 00365 thread::id _M_owner; 00366 unsigned _M_count = 0; 00367 00368 // Predicate type that tests whether the current thread can lock a mutex. 00369 struct _Can_lock 00370 { 00371 // Returns true if the mutex is unlocked or is locked by _M_caller. 00372 bool 00373 operator()() const noexcept 00374 { return _M_mx->_M_count == 0 || _M_mx->_M_owner == _M_caller; } 00375 00376 const recursive_timed_mutex* _M_mx; 00377 thread::id _M_caller; 00378 }; 00379 00380 public: 00381 00382 recursive_timed_mutex() = default; 00383 ~recursive_timed_mutex() { __glibcxx_assert( _M_count == 0 ); } 00384 00385 recursive_timed_mutex(const recursive_timed_mutex&) = delete; 00386 recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; 00387 00388 void 00389 lock() 00390 { 00391 auto __id = this_thread::get_id(); 00392 _Can_lock __can_lock{this, __id}; 00393 unique_lock<mutex> __lk(_M_mut); 00394 _M_cv.wait(__lk, __can_lock); 00395 if (_M_count == -1u) 00396 __throw_system_error(EAGAIN); // [thread.timedmutex.recursive]/3 00397 _M_owner = __id; 00398 ++_M_count; 00399 } 00400 00401 bool 00402 try_lock() 00403 { 00404 auto __id = this_thread::get_id(); 00405 _Can_lock __can_lock{this, __id}; 00406 lock_guard<mutex> __lk(_M_mut); 00407 if (!__can_lock()) 00408 return false; 00409 if (_M_count == -1u) 00410 return false; 00411 _M_owner = __id; 00412 ++_M_count; 00413 return true; 00414 } 00415 00416 template<typename _Rep, typename _Period> 00417 bool 00418 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 00419 { 00420 auto __id = this_thread::get_id(); 00421 _Can_lock __can_lock{this, __id}; 00422 unique_lock<mutex> __lk(_M_mut); 00423 if (!_M_cv.wait_for(__lk, __rtime, __can_lock)) 00424 return false; 00425 if (_M_count == -1u) 00426 return false; 00427 _M_owner = __id; 00428 ++_M_count; 00429 return true; 00430 } 00431 00432 template<typename _Clock, typename _Duration> 00433 bool 00434 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 00435 { 00436 auto __id = this_thread::get_id(); 00437 _Can_lock __can_lock{this, __id}; 00438 unique_lock<mutex> __lk(_M_mut); 00439 if (!_M_cv.wait_until(__lk, __atime, __can_lock)) 00440 return false; 00441 if (_M_count == -1u) 00442 return false; 00443 _M_owner = __id; 00444 ++_M_count; 00445 return true; 00446 } 00447 00448 void 00449 unlock() 00450 { 00451 lock_guard<mutex> __lk(_M_mut); 00452 __glibcxx_assert( _M_owner == this_thread::get_id() ); 00453 __glibcxx_assert( _M_count > 0 ); 00454 if (--_M_count == 0) 00455 { 00456 _M_owner = {}; 00457 _M_cv.notify_one(); 00458 } 00459 } 00460 }; 00461 00462 #endif 00463 #endif // _GLIBCXX_HAS_GTHREADS 00464 00465 template<typename _Lock> 00466 inline unique_lock<_Lock> 00467 __try_to_lock(_Lock& __l) 00468 { return unique_lock<_Lock>{__l, try_to_lock}; } 00469 00470 template<int _Idx, bool _Continue = true> 00471 struct __try_lock_impl 00472 { 00473 template<typename... _Lock> 00474 static void 00475 __do_try_lock(tuple<_Lock&...>& __locks, int& __idx) 00476 { 00477 __idx = _Idx; 00478 auto __lock = std::__try_to_lock(std::get<_Idx>(__locks)); 00479 if (__lock.owns_lock()) 00480 { 00481 constexpr bool __cont = _Idx + 2 < sizeof...(_Lock); 00482 using __try_locker = __try_lock_impl<_Idx + 1, __cont>; 00483 __try_locker::__do_try_lock(__locks, __idx); 00484 if (__idx == -1) 00485 __lock.release(); 00486 } 00487 } 00488 }; 00489 00490 template<int _Idx> 00491 struct __try_lock_impl<_Idx, false> 00492 { 00493 template<typename... _Lock> 00494 static void 00495 __do_try_lock(tuple<_Lock&...>& __locks, int& __idx) 00496 { 00497 __idx = _Idx; 00498 auto __lock = std::__try_to_lock(std::get<_Idx>(__locks)); 00499 if (__lock.owns_lock()) 00500 { 00501 __idx = -1; 00502 __lock.release(); 00503 } 00504 } 00505 }; 00506 00507 /** @brief Generic try_lock. 00508 * @param __l1 Meets Mutex requirements (try_lock() may throw). 00509 * @param __l2 Meets Mutex requirements (try_lock() may throw). 00510 * @param __l3 Meets Mutex requirements (try_lock() may throw). 00511 * @return Returns -1 if all try_lock() calls return true. Otherwise returns 00512 * a 0-based index corresponding to the argument that returned false. 00513 * @post Either all arguments are locked, or none will be. 00514 * 00515 * Sequentially calls try_lock() on each argument. 00516 */ 00517 template<typename _Lock1, typename _Lock2, typename... _Lock3> 00518 int 00519 try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3) 00520 { 00521 int __idx; 00522 auto __locks = std::tie(__l1, __l2, __l3...); 00523 __try_lock_impl<0>::__do_try_lock(__locks, __idx); 00524 return __idx; 00525 } 00526 00527 /** @brief Generic lock. 00528 * @param __l1 Meets Mutex requirements (try_lock() may throw). 00529 * @param __l2 Meets Mutex requirements (try_lock() may throw). 00530 * @param __l3 Meets Mutex requirements (try_lock() may throw). 00531 * @throw An exception thrown by an argument's lock() or try_lock() member. 00532 * @post All arguments are locked. 00533 * 00534 * All arguments are locked via a sequence of calls to lock(), try_lock() 00535 * and unlock(). If the call exits via an exception any locks that were 00536 * obtained will be released. 00537 */ 00538 template<typename _L1, typename _L2, typename... _L3> 00539 void 00540 lock(_L1& __l1, _L2& __l2, _L3&... __l3) 00541 { 00542 while (true) 00543 { 00544 using __try_locker = __try_lock_impl<0, sizeof...(_L3) != 0>; 00545 unique_lock<_L1> __first(__l1); 00546 int __idx; 00547 auto __locks = std::tie(__l2, __l3...); 00548 __try_locker::__do_try_lock(__locks, __idx); 00549 if (__idx == -1) 00550 { 00551 __first.release(); 00552 return; 00553 } 00554 } 00555 } 00556 00557 #ifdef _GLIBCXX_HAS_GTHREADS 00558 /// once_flag 00559 struct once_flag 00560 { 00561 private: 00562 typedef __gthread_once_t __native_type; 00563 __native_type _M_once = __GTHREAD_ONCE_INIT; 00564 00565 public: 00566 /// Constructor 00567 constexpr once_flag() noexcept = default; 00568 00569 /// Deleted copy constructor 00570 once_flag(const once_flag&) = delete; 00571 /// Deleted assignment operator 00572 once_flag& operator=(const once_flag&) = delete; 00573 00574 template<typename _Callable, typename... _Args> 00575 friend void 00576 call_once(once_flag& __once, _Callable&& __f, _Args&&... __args); 00577 }; 00578 00579 #ifdef _GLIBCXX_HAVE_TLS 00580 extern __thread void* __once_callable; 00581 extern __thread void (*__once_call)(); 00582 00583 template<typename _Callable> 00584 inline void 00585 __once_call_impl() 00586 { 00587 (*(_Callable*)__once_callable)(); 00588 } 00589 #else 00590 extern function<void()> __once_functor; 00591 00592 extern void 00593 __set_once_functor_lock_ptr(unique_lock<mutex>*); 00594 00595 extern mutex& 00596 __get_once_mutex(); 00597 #endif 00598 00599 extern "C" void __once_proxy(void); 00600 00601 /// call_once 00602 template<typename _Callable, typename... _Args> 00603 void 00604 call_once(once_flag& __once, _Callable&& __f, _Args&&... __args) 00605 { 00606 #ifdef _GLIBCXX_HAVE_TLS 00607 auto __bound_functor = std::__bind_simple(std::forward<_Callable>(__f), 00608 std::forward<_Args>(__args)...); 00609 __once_callable = std::__addressof(__bound_functor); 00610 __once_call = &__once_call_impl<decltype(__bound_functor)>; 00611 #else 00612 unique_lock<mutex> __functor_lock(__get_once_mutex()); 00613 auto __callable = std::__bind_simple(std::forward<_Callable>(__f), 00614 std::forward<_Args>(__args)...); 00615 __once_functor = [&]() { __callable(); }; 00616 __set_once_functor_lock_ptr(&__functor_lock); 00617 #endif 00618 00619 int __e = __gthread_once(&__once._M_once, &__once_proxy); 00620 00621 #ifndef _GLIBCXX_HAVE_TLS 00622 if (__functor_lock) 00623 __set_once_functor_lock_ptr(0); 00624 #endif 00625 00626 if (__e) 00627 __throw_system_error(__e); 00628 } 00629 #endif // _GLIBCXX_HAS_GTHREADS 00630 00631 // @} group mutexes 00632 _GLIBCXX_END_NAMESPACE_VERSION 00633 } // namespace 00634 #endif // _GLIBCXX_USE_C99_STDINT_TR1 00635 00636 #endif // C++11 00637 00638 #endif // _GLIBCXX_MUTEX