libstdc++
|
00001 // <mutex> -*- C++ -*- 00002 00003 // Copyright (C) 2003-2017 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 <system_error> 00043 #include <bits/std_mutex.h> 00044 #if ! _GTHREAD_USE_MUTEX_TIMEDLOCK 00045 # include <condition_variable> 00046 # include <thread> 00047 #endif 00048 #ifndef _GLIBCXX_HAVE_TLS 00049 # include <bits/std_function.h> 00050 #endif 00051 00052 #ifdef _GLIBCXX_USE_C99_STDINT_TR1 00053 00054 namespace std _GLIBCXX_VISIBILITY(default) 00055 { 00056 _GLIBCXX_BEGIN_NAMESPACE_VERSION 00057 00058 /** 00059 * @ingroup mutexes 00060 * @{ 00061 */ 00062 00063 #ifdef _GLIBCXX_HAS_GTHREADS 00064 00065 // Common base class for std::recursive_mutex and std::recursive_timed_mutex 00066 class __recursive_mutex_base 00067 { 00068 protected: 00069 typedef __gthread_recursive_mutex_t __native_type; 00070 00071 __recursive_mutex_base(const __recursive_mutex_base&) = delete; 00072 __recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete; 00073 00074 #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT 00075 __native_type _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT; 00076 00077 __recursive_mutex_base() = default; 00078 #else 00079 __native_type _M_mutex; 00080 00081 __recursive_mutex_base() 00082 { 00083 // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may) 00084 __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); 00085 } 00086 00087 ~__recursive_mutex_base() 00088 { __gthread_recursive_mutex_destroy(&_M_mutex); } 00089 #endif 00090 }; 00091 00092 /// The standard recursive mutex type. 00093 class recursive_mutex : private __recursive_mutex_base 00094 { 00095 public: 00096 typedef __native_type* native_handle_type; 00097 00098 recursive_mutex() = default; 00099 ~recursive_mutex() = default; 00100 00101 recursive_mutex(const recursive_mutex&) = delete; 00102 recursive_mutex& operator=(const recursive_mutex&) = delete; 00103 00104 void 00105 lock() 00106 { 00107 int __e = __gthread_recursive_mutex_lock(&_M_mutex); 00108 00109 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 00110 if (__e) 00111 __throw_system_error(__e); 00112 } 00113 00114 bool 00115 try_lock() noexcept 00116 { 00117 // XXX EINVAL, EAGAIN, EBUSY 00118 return !__gthread_recursive_mutex_trylock(&_M_mutex); 00119 } 00120 00121 void 00122 unlock() 00123 { 00124 // XXX EINVAL, EAGAIN, EBUSY 00125 __gthread_recursive_mutex_unlock(&_M_mutex); 00126 } 00127 00128 native_handle_type 00129 native_handle() noexcept 00130 { return &_M_mutex; } 00131 }; 00132 00133 #if _GTHREAD_USE_MUTEX_TIMEDLOCK 00134 template<typename _Derived> 00135 class __timed_mutex_impl 00136 { 00137 protected: 00138 typedef chrono::high_resolution_clock __clock_t; 00139 00140 template<typename _Rep, typename _Period> 00141 bool 00142 _M_try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 00143 { 00144 using chrono::steady_clock; 00145 auto __rt = chrono::duration_cast<steady_clock::duration>(__rtime); 00146 if (ratio_greater<steady_clock::period, _Period>()) 00147 ++__rt; 00148 return _M_try_lock_until(steady_clock::now() + __rt); 00149 } 00150 00151 template<typename _Duration> 00152 bool 00153 _M_try_lock_until(const chrono::time_point<__clock_t, 00154 _Duration>& __atime) 00155 { 00156 auto __s = chrono::time_point_cast<chrono::seconds>(__atime); 00157 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 00158 00159 __gthread_time_t __ts = { 00160 static_cast<std::time_t>(__s.time_since_epoch().count()), 00161 static_cast<long>(__ns.count()) 00162 }; 00163 00164 return static_cast<_Derived*>(this)->_M_timedlock(__ts); 00165 } 00166 00167 template<typename _Clock, typename _Duration> 00168 bool 00169 _M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 00170 { 00171 auto __rtime = __atime - _Clock::now(); 00172 return _M_try_lock_until(__clock_t::now() + __rtime); 00173 } 00174 }; 00175 00176 /// The standard timed mutex type. 00177 class timed_mutex 00178 : private __mutex_base, public __timed_mutex_impl<timed_mutex> 00179 { 00180 public: 00181 typedef __native_type* native_handle_type; 00182 00183 timed_mutex() = default; 00184 ~timed_mutex() = default; 00185 00186 timed_mutex(const timed_mutex&) = delete; 00187 timed_mutex& operator=(const timed_mutex&) = delete; 00188 00189 void 00190 lock() 00191 { 00192 int __e = __gthread_mutex_lock(&_M_mutex); 00193 00194 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 00195 if (__e) 00196 __throw_system_error(__e); 00197 } 00198 00199 bool 00200 try_lock() noexcept 00201 { 00202 // XXX EINVAL, EAGAIN, EBUSY 00203 return !__gthread_mutex_trylock(&_M_mutex); 00204 } 00205 00206 template <class _Rep, class _Period> 00207 bool 00208 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 00209 { return _M_try_lock_for(__rtime); } 00210 00211 template <class _Clock, class _Duration> 00212 bool 00213 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 00214 { return _M_try_lock_until(__atime); } 00215 00216 void 00217 unlock() 00218 { 00219 // XXX EINVAL, EAGAIN, EBUSY 00220 __gthread_mutex_unlock(&_M_mutex); 00221 } 00222 00223 native_handle_type 00224 native_handle() noexcept 00225 { return &_M_mutex; } 00226 00227 private: 00228 friend class __timed_mutex_impl<timed_mutex>; 00229 00230 bool 00231 _M_timedlock(const __gthread_time_t& __ts) 00232 { return !__gthread_mutex_timedlock(&_M_mutex, &__ts); } 00233 }; 00234 00235 /// recursive_timed_mutex 00236 class recursive_timed_mutex 00237 : private __recursive_mutex_base, 00238 public __timed_mutex_impl<recursive_timed_mutex> 00239 { 00240 public: 00241 typedef __native_type* native_handle_type; 00242 00243 recursive_timed_mutex() = default; 00244 ~recursive_timed_mutex() = default; 00245 00246 recursive_timed_mutex(const recursive_timed_mutex&) = delete; 00247 recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; 00248 00249 void 00250 lock() 00251 { 00252 int __e = __gthread_recursive_mutex_lock(&_M_mutex); 00253 00254 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 00255 if (__e) 00256 __throw_system_error(__e); 00257 } 00258 00259 bool 00260 try_lock() noexcept 00261 { 00262 // XXX EINVAL, EAGAIN, EBUSY 00263 return !__gthread_recursive_mutex_trylock(&_M_mutex); 00264 } 00265 00266 template <class _Rep, class _Period> 00267 bool 00268 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 00269 { return _M_try_lock_for(__rtime); } 00270 00271 template <class _Clock, class _Duration> 00272 bool 00273 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 00274 { return _M_try_lock_until(__atime); } 00275 00276 void 00277 unlock() 00278 { 00279 // XXX EINVAL, EAGAIN, EBUSY 00280 __gthread_recursive_mutex_unlock(&_M_mutex); 00281 } 00282 00283 native_handle_type 00284 native_handle() noexcept 00285 { return &_M_mutex; } 00286 00287 private: 00288 friend class __timed_mutex_impl<recursive_timed_mutex>; 00289 00290 bool 00291 _M_timedlock(const __gthread_time_t& __ts) 00292 { return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts); } 00293 }; 00294 00295 #else // !_GTHREAD_USE_MUTEX_TIMEDLOCK 00296 00297 /// timed_mutex 00298 class timed_mutex 00299 { 00300 mutex _M_mut; 00301 condition_variable _M_cv; 00302 bool _M_locked = false; 00303 00304 public: 00305 00306 timed_mutex() = default; 00307 ~timed_mutex() { __glibcxx_assert( !_M_locked ); } 00308 00309 timed_mutex(const timed_mutex&) = delete; 00310 timed_mutex& operator=(const timed_mutex&) = delete; 00311 00312 void 00313 lock() 00314 { 00315 unique_lock<mutex> __lk(_M_mut); 00316 _M_cv.wait(__lk, [&]{ return !_M_locked; }); 00317 _M_locked = true; 00318 } 00319 00320 bool 00321 try_lock() 00322 { 00323 lock_guard<mutex> __lk(_M_mut); 00324 if (_M_locked) 00325 return false; 00326 _M_locked = true; 00327 return true; 00328 } 00329 00330 template<typename _Rep, typename _Period> 00331 bool 00332 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 00333 { 00334 unique_lock<mutex> __lk(_M_mut); 00335 if (!_M_cv.wait_for(__lk, __rtime, [&]{ return !_M_locked; })) 00336 return false; 00337 _M_locked = true; 00338 return true; 00339 } 00340 00341 template<typename _Clock, typename _Duration> 00342 bool 00343 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 00344 { 00345 unique_lock<mutex> __lk(_M_mut); 00346 if (!_M_cv.wait_until(__lk, __atime, [&]{ return !_M_locked; })) 00347 return false; 00348 _M_locked = true; 00349 return true; 00350 } 00351 00352 void 00353 unlock() 00354 { 00355 lock_guard<mutex> __lk(_M_mut); 00356 __glibcxx_assert( _M_locked ); 00357 _M_locked = false; 00358 _M_cv.notify_one(); 00359 } 00360 }; 00361 00362 /// recursive_timed_mutex 00363 class recursive_timed_mutex 00364 { 00365 mutex _M_mut; 00366 condition_variable _M_cv; 00367 thread::id _M_owner; 00368 unsigned _M_count = 0; 00369 00370 // Predicate type that tests whether the current thread can lock a mutex. 00371 struct _Can_lock 00372 { 00373 // Returns true if the mutex is unlocked or is locked by _M_caller. 00374 bool 00375 operator()() const noexcept 00376 { return _M_mx->_M_count == 0 || _M_mx->_M_owner == _M_caller; } 00377 00378 const recursive_timed_mutex* _M_mx; 00379 thread::id _M_caller; 00380 }; 00381 00382 public: 00383 00384 recursive_timed_mutex() = default; 00385 ~recursive_timed_mutex() { __glibcxx_assert( _M_count == 0 ); } 00386 00387 recursive_timed_mutex(const recursive_timed_mutex&) = delete; 00388 recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; 00389 00390 void 00391 lock() 00392 { 00393 auto __id = this_thread::get_id(); 00394 _Can_lock __can_lock{this, __id}; 00395 unique_lock<mutex> __lk(_M_mut); 00396 _M_cv.wait(__lk, __can_lock); 00397 if (_M_count == -1u) 00398 __throw_system_error(EAGAIN); // [thread.timedmutex.recursive]/3 00399 _M_owner = __id; 00400 ++_M_count; 00401 } 00402 00403 bool 00404 try_lock() 00405 { 00406 auto __id = this_thread::get_id(); 00407 _Can_lock __can_lock{this, __id}; 00408 lock_guard<mutex> __lk(_M_mut); 00409 if (!__can_lock()) 00410 return false; 00411 if (_M_count == -1u) 00412 return false; 00413 _M_owner = __id; 00414 ++_M_count; 00415 return true; 00416 } 00417 00418 template<typename _Rep, typename _Period> 00419 bool 00420 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 00421 { 00422 auto __id = this_thread::get_id(); 00423 _Can_lock __can_lock{this, __id}; 00424 unique_lock<mutex> __lk(_M_mut); 00425 if (!_M_cv.wait_for(__lk, __rtime, __can_lock)) 00426 return false; 00427 if (_M_count == -1u) 00428 return false; 00429 _M_owner = __id; 00430 ++_M_count; 00431 return true; 00432 } 00433 00434 template<typename _Clock, typename _Duration> 00435 bool 00436 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 00437 { 00438 auto __id = this_thread::get_id(); 00439 _Can_lock __can_lock{this, __id}; 00440 unique_lock<mutex> __lk(_M_mut); 00441 if (!_M_cv.wait_until(__lk, __atime, __can_lock)) 00442 return false; 00443 if (_M_count == -1u) 00444 return false; 00445 _M_owner = __id; 00446 ++_M_count; 00447 return true; 00448 } 00449 00450 void 00451 unlock() 00452 { 00453 lock_guard<mutex> __lk(_M_mut); 00454 __glibcxx_assert( _M_owner == this_thread::get_id() ); 00455 __glibcxx_assert( _M_count > 0 ); 00456 if (--_M_count == 0) 00457 { 00458 _M_owner = {}; 00459 _M_cv.notify_one(); 00460 } 00461 } 00462 }; 00463 00464 #endif 00465 #endif // _GLIBCXX_HAS_GTHREADS 00466 00467 template<typename _Lock> 00468 inline unique_lock<_Lock> 00469 __try_to_lock(_Lock& __l) 00470 { return unique_lock<_Lock>{__l, try_to_lock}; } 00471 00472 template<int _Idx, bool _Continue = true> 00473 struct __try_lock_impl 00474 { 00475 template<typename... _Lock> 00476 static void 00477 __do_try_lock(tuple<_Lock&...>& __locks, int& __idx) 00478 { 00479 __idx = _Idx; 00480 auto __lock = std::__try_to_lock(std::get<_Idx>(__locks)); 00481 if (__lock.owns_lock()) 00482 { 00483 constexpr bool __cont = _Idx + 2 < sizeof...(_Lock); 00484 using __try_locker = __try_lock_impl<_Idx + 1, __cont>; 00485 __try_locker::__do_try_lock(__locks, __idx); 00486 if (__idx == -1) 00487 __lock.release(); 00488 } 00489 } 00490 }; 00491 00492 template<int _Idx> 00493 struct __try_lock_impl<_Idx, false> 00494 { 00495 template<typename... _Lock> 00496 static void 00497 __do_try_lock(tuple<_Lock&...>& __locks, int& __idx) 00498 { 00499 __idx = _Idx; 00500 auto __lock = std::__try_to_lock(std::get<_Idx>(__locks)); 00501 if (__lock.owns_lock()) 00502 { 00503 __idx = -1; 00504 __lock.release(); 00505 } 00506 } 00507 }; 00508 00509 /** @brief Generic try_lock. 00510 * @param __l1 Meets Mutex requirements (try_lock() may throw). 00511 * @param __l2 Meets Mutex requirements (try_lock() may throw). 00512 * @param __l3 Meets Mutex requirements (try_lock() may throw). 00513 * @return Returns -1 if all try_lock() calls return true. Otherwise returns 00514 * a 0-based index corresponding to the argument that returned false. 00515 * @post Either all arguments are locked, or none will be. 00516 * 00517 * Sequentially calls try_lock() on each argument. 00518 */ 00519 template<typename _Lock1, typename _Lock2, typename... _Lock3> 00520 int 00521 try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3) 00522 { 00523 int __idx; 00524 auto __locks = std::tie(__l1, __l2, __l3...); 00525 __try_lock_impl<0>::__do_try_lock(__locks, __idx); 00526 return __idx; 00527 } 00528 00529 /** @brief Generic lock. 00530 * @param __l1 Meets Mutex requirements (try_lock() may throw). 00531 * @param __l2 Meets Mutex requirements (try_lock() may throw). 00532 * @param __l3 Meets Mutex requirements (try_lock() may throw). 00533 * @throw An exception thrown by an argument's lock() or try_lock() member. 00534 * @post All arguments are locked. 00535 * 00536 * All arguments are locked via a sequence of calls to lock(), try_lock() 00537 * and unlock(). If the call exits via an exception any locks that were 00538 * obtained will be released. 00539 */ 00540 template<typename _L1, typename _L2, typename... _L3> 00541 void 00542 lock(_L1& __l1, _L2& __l2, _L3&... __l3) 00543 { 00544 while (true) 00545 { 00546 using __try_locker = __try_lock_impl<0, sizeof...(_L3) != 0>; 00547 unique_lock<_L1> __first(__l1); 00548 int __idx; 00549 auto __locks = std::tie(__l2, __l3...); 00550 __try_locker::__do_try_lock(__locks, __idx); 00551 if (__idx == -1) 00552 { 00553 __first.release(); 00554 return; 00555 } 00556 } 00557 } 00558 00559 #if __cplusplus >= 201703L 00560 #define __cpp_lib_scoped_lock 201703 00561 /** @brief A scoped lock type for multiple lockable objects. 00562 * 00563 * A scoped_lock controls mutex ownership within a scope, releasing 00564 * ownership in the destructor. 00565 */ 00566 template<typename... _MutexTypes> 00567 class scoped_lock 00568 { 00569 public: 00570 explicit scoped_lock(_MutexTypes&... __m) : _M_devices(std::tie(__m...)) 00571 { std::lock(__m...); } 00572 00573 explicit scoped_lock(adopt_lock_t, _MutexTypes&... __m) noexcept 00574 : _M_devices(std::tie(__m...)) 00575 { } // calling thread owns mutex 00576 00577 ~scoped_lock() 00578 { 00579 std::apply([](_MutexTypes&... __m) { 00580 char __i[] __attribute__((__unused__)) = { (__m.unlock(), 0)... }; 00581 }, _M_devices); 00582 } 00583 00584 scoped_lock(const scoped_lock&) = delete; 00585 scoped_lock& operator=(const scoped_lock&) = delete; 00586 00587 private: 00588 tuple<_MutexTypes&...> _M_devices; 00589 }; 00590 00591 template<> 00592 class scoped_lock<> 00593 { 00594 public: 00595 explicit scoped_lock() = default; 00596 explicit scoped_lock(adopt_lock_t) noexcept { } 00597 ~scoped_lock() = default; 00598 00599 scoped_lock(const scoped_lock&) = delete; 00600 scoped_lock& operator=(const scoped_lock&) = delete; 00601 }; 00602 00603 template<typename _Mutex> 00604 class scoped_lock<_Mutex> 00605 { 00606 public: 00607 using mutex_type = _Mutex; 00608 00609 explicit scoped_lock(mutex_type& __m) : _M_device(__m) 00610 { _M_device.lock(); } 00611 00612 explicit scoped_lock(adopt_lock_t, mutex_type& __m) noexcept 00613 : _M_device(__m) 00614 { } // calling thread owns mutex 00615 00616 ~scoped_lock() 00617 { _M_device.unlock(); } 00618 00619 scoped_lock(const scoped_lock&) = delete; 00620 scoped_lock& operator=(const scoped_lock&) = delete; 00621 00622 private: 00623 mutex_type& _M_device; 00624 }; 00625 #endif // C++17 00626 00627 #ifdef _GLIBCXX_HAS_GTHREADS 00628 /// once_flag 00629 struct once_flag 00630 { 00631 private: 00632 typedef __gthread_once_t __native_type; 00633 __native_type _M_once = __GTHREAD_ONCE_INIT; 00634 00635 public: 00636 /// Constructor 00637 constexpr once_flag() noexcept = default; 00638 00639 /// Deleted copy constructor 00640 once_flag(const once_flag&) = delete; 00641 /// Deleted assignment operator 00642 once_flag& operator=(const once_flag&) = delete; 00643 00644 template<typename _Callable, typename... _Args> 00645 friend void 00646 call_once(once_flag& __once, _Callable&& __f, _Args&&... __args); 00647 }; 00648 00649 #ifdef _GLIBCXX_HAVE_TLS 00650 extern __thread void* __once_callable; 00651 extern __thread void (*__once_call)(); 00652 #else 00653 extern function<void()> __once_functor; 00654 00655 extern void 00656 __set_once_functor_lock_ptr(unique_lock<mutex>*); 00657 00658 extern mutex& 00659 __get_once_mutex(); 00660 #endif 00661 00662 extern "C" void __once_proxy(void); 00663 00664 /// call_once 00665 template<typename _Callable, typename... _Args> 00666 void 00667 call_once(once_flag& __once, _Callable&& __f, _Args&&... __args) 00668 { 00669 // _GLIBCXX_RESOLVE_LIB_DEFECTS 00670 // 2442. call_once() shouldn't DECAY_COPY() 00671 auto __callable = [&] { 00672 std::__invoke(std::forward<_Callable>(__f), 00673 std::forward<_Args>(__args)...); 00674 }; 00675 #ifdef _GLIBCXX_HAVE_TLS 00676 __once_callable = std::__addressof(__callable); 00677 __once_call = []{ (*(decltype(__callable)*)__once_callable)(); }; 00678 #else 00679 unique_lock<mutex> __functor_lock(__get_once_mutex()); 00680 __once_functor = __callable; 00681 __set_once_functor_lock_ptr(&__functor_lock); 00682 #endif 00683 00684 int __e = __gthread_once(&__once._M_once, &__once_proxy); 00685 00686 #ifndef _GLIBCXX_HAVE_TLS 00687 if (__functor_lock) 00688 __set_once_functor_lock_ptr(0); 00689 #endif 00690 00691 #ifdef __clang_analyzer__ 00692 // PR libstdc++/82481 00693 __once_callable = nullptr; 00694 __once_call = nullptr; 00695 #endif 00696 00697 if (__e) 00698 __throw_system_error(__e); 00699 } 00700 #endif // _GLIBCXX_HAS_GTHREADS 00701 00702 // @} group mutexes 00703 _GLIBCXX_END_NAMESPACE_VERSION 00704 } // namespace 00705 #endif // _GLIBCXX_USE_C99_STDINT_TR1 00706 00707 #endif // C++11 00708 00709 #endif // _GLIBCXX_MUTEX