libstdc++
mutex
Go to the documentation of this file.
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