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