libstdc++
condition_variable
Go to the documentation of this file.
00001 // <condition_variable> -*- C++ -*-
00002 
00003 // Copyright (C) 2008-2013 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/condition_variable
00026  *  This is a Standard C++ Library header.
00027  */
00028 
00029 #ifndef _GLIBCXX_CONDITION_VARIABLE
00030 #define _GLIBCXX_CONDITION_VARIABLE 1
00031 
00032 #pragma GCC system_header
00033 
00034 #if __cplusplus < 201103L
00035 # include <bits/c++0x_warning.h>
00036 #else
00037 
00038 #include <chrono>
00039 #include <mutex> // unique_lock
00040 
00041 #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
00042 
00043 namespace std _GLIBCXX_VISIBILITY(default)
00044 {
00045 _GLIBCXX_BEGIN_NAMESPACE_VERSION
00046 
00047   /**
00048    * @defgroup condition_variables Condition Variables
00049    * @ingroup concurrency
00050    *
00051    * Classes for condition_variable support.
00052    * @{
00053    */
00054 
00055   /// cv_status
00056   enum class cv_status { no_timeout, timeout };
00057   
00058   /// condition_variable
00059   class condition_variable
00060   {
00061     typedef chrono::system_clock    __clock_t;
00062     typedef __gthread_cond_t        __native_type;
00063 
00064 #ifdef __GTHREAD_COND_INIT
00065     __native_type           _M_cond = __GTHREAD_COND_INIT;
00066 #else
00067     __native_type           _M_cond;
00068 #endif
00069 
00070   public:
00071     typedef __native_type*      native_handle_type;
00072 
00073     condition_variable() noexcept;
00074     ~condition_variable() noexcept;
00075 
00076     condition_variable(const condition_variable&) = delete;
00077     condition_variable& operator=(const condition_variable&) = delete;
00078 
00079     void
00080     notify_one() noexcept;
00081 
00082     void
00083     notify_all() noexcept;
00084 
00085     void
00086     wait(unique_lock<mutex>& __lock);
00087 
00088     template<typename _Predicate>
00089       void
00090       wait(unique_lock<mutex>& __lock, _Predicate __p)
00091       {
00092     while (!__p())
00093       wait(__lock);
00094       }
00095 
00096     template<typename _Duration>
00097       cv_status
00098       wait_until(unique_lock<mutex>& __lock,
00099          const chrono::time_point<__clock_t, _Duration>& __atime)
00100       { return __wait_until_impl(__lock, __atime); }
00101 
00102     template<typename _Clock, typename _Duration>
00103       cv_status
00104       wait_until(unique_lock<mutex>& __lock,
00105          const chrono::time_point<_Clock, _Duration>& __atime)
00106       {
00107     // DR 887 - Sync unknown clock to known clock.
00108     const typename _Clock::time_point __c_entry = _Clock::now();
00109     const __clock_t::time_point __s_entry = __clock_t::now();
00110     const auto __delta = __atime - __c_entry;
00111     const auto __s_atime = __s_entry + __delta;
00112 
00113     return __wait_until_impl(__lock, __s_atime);
00114       }
00115 
00116     template<typename _Clock, typename _Duration, typename _Predicate>
00117       bool
00118       wait_until(unique_lock<mutex>& __lock,
00119          const chrono::time_point<_Clock, _Duration>& __atime,
00120          _Predicate __p)
00121       {
00122     while (!__p())
00123       if (wait_until(__lock, __atime) == cv_status::timeout)
00124         return __p();
00125     return true;
00126       }
00127 
00128     template<typename _Rep, typename _Period>
00129       cv_status
00130       wait_for(unique_lock<mutex>& __lock,
00131            const chrono::duration<_Rep, _Period>& __rtime)
00132       { return wait_until(__lock, __clock_t::now() + __rtime); }
00133 
00134     template<typename _Rep, typename _Period, typename _Predicate>
00135       bool
00136       wait_for(unique_lock<mutex>& __lock,
00137            const chrono::duration<_Rep, _Period>& __rtime,
00138            _Predicate __p)
00139       { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); }
00140 
00141     native_handle_type
00142     native_handle()
00143     { return &_M_cond; }
00144 
00145   private:
00146     template<typename _Dur>
00147       cv_status
00148       __wait_until_impl(unique_lock<mutex>& __lock,
00149             const chrono::time_point<__clock_t, _Dur>& __atime)
00150       {
00151     auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
00152     auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
00153 
00154     __gthread_time_t __ts =
00155       {
00156         static_cast<std::time_t>(__s.time_since_epoch().count()),
00157         static_cast<long>(__ns.count())
00158       };
00159 
00160     __gthread_cond_timedwait(&_M_cond, __lock.mutex()->native_handle(),
00161                  &__ts);
00162 
00163     return (__clock_t::now() < __atime
00164         ? cv_status::no_timeout : cv_status::timeout);
00165       }
00166   };
00167 
00168   /// condition_variable_any
00169   // Like above, but mutex is not required to have try_lock.
00170   class condition_variable_any
00171   {
00172     typedef chrono::system_clock    __clock_t;
00173     condition_variable          _M_cond;
00174     mutex               _M_mutex;
00175 
00176     // scoped unlock - unlocks in ctor, re-locks in dtor
00177     template<typename _Lock>
00178       struct _Unlock
00179       {
00180     explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); }
00181 
00182     ~_Unlock() noexcept(false)
00183     {
00184       if (uncaught_exception())
00185         __try { _M_lock.lock(); } __catch(...) { }
00186       else
00187         _M_lock.lock();
00188     }
00189 
00190     _Unlock(const _Unlock&) = delete;
00191     _Unlock& operator=(const _Unlock&) = delete;
00192 
00193     _Lock& _M_lock;
00194       };
00195 
00196   public:
00197 
00198     condition_variable_any() noexcept;
00199     ~condition_variable_any() noexcept;
00200 
00201     condition_variable_any(const condition_variable_any&) = delete;
00202     condition_variable_any& operator=(const condition_variable_any&) = delete;
00203 
00204     void
00205     notify_one() noexcept
00206     {
00207       lock_guard<mutex> __lock(_M_mutex);
00208       _M_cond.notify_one();
00209     }
00210 
00211     void
00212     notify_all() noexcept
00213     {
00214       lock_guard<mutex> __lock(_M_mutex);
00215       _M_cond.notify_all();
00216     }
00217 
00218     template<typename _Lock>
00219       void
00220       wait(_Lock& __lock)
00221       {
00222     unique_lock<mutex> __my_lock(_M_mutex);
00223     _Unlock<_Lock> __unlock(__lock);
00224     // _M_mutex must be unlocked before re-locking __lock so move
00225     // ownership of _M_mutex lock to an object with shorter lifetime.
00226     unique_lock<mutex> __my_lock2(std::move(__my_lock));
00227     _M_cond.wait(__my_lock2);
00228       }
00229       
00230 
00231     template<typename _Lock, typename _Predicate>
00232       void
00233       wait(_Lock& __lock, _Predicate __p)
00234       {
00235     while (!__p())
00236       wait(__lock);
00237       }
00238 
00239     template<typename _Lock, typename _Clock, typename _Duration>
00240       cv_status
00241       wait_until(_Lock& __lock,
00242          const chrono::time_point<_Clock, _Duration>& __atime)
00243       {
00244     unique_lock<mutex> __my_lock(_M_mutex);
00245     _Unlock<_Lock> __unlock(__lock);
00246     // _M_mutex must be unlocked before re-locking __lock so move
00247     // ownership of _M_mutex lock to an object with shorter lifetime.
00248     unique_lock<mutex> __my_lock2(std::move(__my_lock));
00249     return _M_cond.wait_until(__my_lock2, __atime);
00250       }
00251 
00252     template<typename _Lock, typename _Clock,
00253          typename _Duration, typename _Predicate>
00254       bool
00255       wait_until(_Lock& __lock,
00256          const chrono::time_point<_Clock, _Duration>& __atime,
00257          _Predicate __p)
00258       {
00259     while (!__p())
00260       if (wait_until(__lock, __atime) == cv_status::timeout)
00261         return __p();
00262     return true;
00263       }
00264 
00265     template<typename _Lock, typename _Rep, typename _Period>
00266       cv_status
00267       wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __rtime)
00268       { return wait_until(__lock, __clock_t::now() + __rtime); }
00269 
00270     template<typename _Lock, typename _Rep,
00271          typename _Period, typename _Predicate>
00272       bool
00273       wait_for(_Lock& __lock,
00274            const chrono::duration<_Rep, _Period>& __rtime, _Predicate __p)
00275       { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); }
00276   };
00277 
00278   // @} group condition_variables
00279 _GLIBCXX_END_NAMESPACE_VERSION
00280 } // namespace
00281 
00282 #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
00283 
00284 #endif // C++11
00285 
00286 #endif // _GLIBCXX_CONDITION_VARIABLE