libstdc++
mutex
Go to the documentation of this file.
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 #else
00583   extern function<void()> __once_functor;
00584 
00585   extern void
00586   __set_once_functor_lock_ptr(unique_lock<mutex>*);
00587 
00588   extern mutex&
00589   __get_once_mutex();
00590 #endif
00591 
00592   extern "C" void __once_proxy(void);
00593 
00594   /// call_once
00595   template<typename _Callable, typename... _Args>
00596     void
00597     call_once(once_flag& __once, _Callable&& __f, _Args&&... __args)
00598     {
00599       // _GLIBCXX_RESOLVE_LIB_DEFECTS
00600       // 2442. call_once() shouldn't DECAY_COPY()
00601       auto __callable = [&] {
00602           std::__invoke(std::forward<_Callable>(__f),
00603                         std::forward<_Args>(__args)...);
00604       };
00605 #ifdef _GLIBCXX_HAVE_TLS
00606       __once_callable = std::__addressof(__callable);
00607       __once_call = []{ (*(decltype(__callable)*)__once_callable)(); };
00608 #else
00609       unique_lock<mutex> __functor_lock(__get_once_mutex());
00610       __once_functor = __callable;
00611       __set_once_functor_lock_ptr(&__functor_lock);
00612 #endif
00613 
00614       int __e = __gthread_once(&__once._M_once, &__once_proxy);
00615 
00616 #ifndef _GLIBCXX_HAVE_TLS
00617       if (__functor_lock)
00618         __set_once_functor_lock_ptr(0);
00619 #endif
00620 
00621       if (__e)
00622         __throw_system_error(__e);
00623     }
00624 #endif // _GLIBCXX_HAS_GTHREADS
00625 
00626   // @} group mutexes
00627 _GLIBCXX_END_NAMESPACE_VERSION
00628 } // namespace
00629 #endif // _GLIBCXX_USE_C99_STDINT_TR1
00630 
00631 #endif // C++11
00632 
00633 #endif // _GLIBCXX_MUTEX