libstdc++
condition_variable
Go to the documentation of this file.
00001 // <condition_variable> -*- C++ -*-
00002 
00003 // Copyright (C) 2008, 2009, 2010, 2011, 2012 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 #ifndef __GXX_EXPERIMENTAL_CXX0X__
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 chrono::nanoseconds __delta = __atime - __c_entry;
00111     const __clock_t::time_point __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 _Clock, typename _Duration>
00147       cv_status
00148       __wait_until_impl(unique_lock<mutex>& __lock,
00149             const chrono::time_point<_Clock, _Duration>& __atime)
00150       {
00151     chrono::time_point<__clock_t, chrono::seconds> __s =
00152       chrono::time_point_cast<chrono::seconds>(__atime);
00153 
00154     chrono::nanoseconds __ns =
00155       chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
00156 
00157     __gthread_time_t __ts =
00158       {
00159         static_cast<std::time_t>(__s.time_since_epoch().count()),
00160         static_cast<long>(__ns.count())
00161       };
00162 
00163     __gthread_cond_timedwait(&_M_cond, __lock.mutex()->native_handle(),
00164                  &__ts);
00165 
00166     return (_Clock::now() < __atime
00167         ? cv_status::no_timeout : cv_status::timeout);
00168       }
00169   };
00170 
00171   /// condition_variable_any
00172   // Like above, but mutex is not required to have try_lock.
00173   class condition_variable_any
00174   {
00175     typedef chrono::system_clock    __clock_t;
00176     condition_variable          _M_cond;
00177     mutex               _M_mutex;
00178 
00179     // scoped unlock - unlocks in ctor, re-locks in dtor
00180     template<typename _Lock>
00181       struct _Unlock
00182       {
00183     explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); }
00184 
00185     ~_Unlock() noexcept(false)
00186     {
00187       if (uncaught_exception())
00188         __try { _M_lock.lock(); } __catch(...) { }
00189       else
00190         _M_lock.lock();
00191     }
00192 
00193     _Unlock(const _Unlock&) = delete;
00194     _Unlock& operator=(const _Unlock&) = delete;
00195 
00196     _Lock& _M_lock;
00197       };
00198 
00199   public:
00200 
00201     condition_variable_any() noexcept;
00202     ~condition_variable_any() noexcept;
00203 
00204     condition_variable_any(const condition_variable_any&) = delete;
00205     condition_variable_any& operator=(const condition_variable_any&) = delete;
00206 
00207     void
00208     notify_one() noexcept
00209     {
00210       lock_guard<mutex> __lock(_M_mutex);
00211       _M_cond.notify_one();
00212     }
00213 
00214     void
00215     notify_all() noexcept
00216     {
00217       lock_guard<mutex> __lock(_M_mutex);
00218       _M_cond.notify_all();
00219     }
00220 
00221     template<typename _Lock>
00222       void
00223       wait(_Lock& __lock)
00224       {
00225     unique_lock<mutex> __my_lock(_M_mutex);
00226     _Unlock<_Lock> __unlock(__lock);
00227     // _M_mutex must be unlocked before re-locking __lock so move
00228     // ownership of _M_mutex lock to an object with shorter lifetime.
00229     unique_lock<mutex> __my_lock2(std::move(__my_lock));
00230     _M_cond.wait(__my_lock2);
00231       }
00232       
00233 
00234     template<typename _Lock, typename _Predicate>
00235       void
00236       wait(_Lock& __lock, _Predicate __p)
00237       {
00238     while (!__p())
00239       wait(__lock);
00240       }
00241 
00242     template<typename _Lock, typename _Clock, typename _Duration>
00243       cv_status
00244       wait_until(_Lock& __lock,
00245          const chrono::time_point<_Clock, _Duration>& __atime)
00246       {
00247     unique_lock<mutex> __my_lock(_M_mutex);
00248     _Unlock<_Lock> __unlock(__lock);
00249     // _M_mutex must be unlocked before re-locking __lock so move
00250     // ownership of _M_mutex lock to an object with shorter lifetime.
00251     unique_lock<mutex> __my_lock2(std::move(__my_lock));
00252     return _M_cond.wait_until(__my_lock2, __atime);
00253       }
00254 
00255     template<typename _Lock, typename _Clock,
00256          typename _Duration, typename _Predicate>
00257       bool
00258       wait_until(_Lock& __lock,
00259          const chrono::time_point<_Clock, _Duration>& __atime,
00260          _Predicate __p)
00261       {
00262     while (!__p())
00263       if (wait_until(__lock, __atime) == cv_status::timeout)
00264         return __p();
00265     return true;
00266       }
00267 
00268     template<typename _Lock, typename _Rep, typename _Period>
00269       cv_status
00270       wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __rtime)
00271       { return wait_until(__lock, __clock_t::now() + __rtime); }
00272 
00273     template<typename _Lock, typename _Rep,
00274          typename _Period, typename _Predicate>
00275       bool
00276       wait_for(_Lock& __lock,
00277            const chrono::duration<_Rep, _Period>& __rtime, _Predicate __p)
00278       { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); }
00279   };
00280 
00281   // @} group condition_variables
00282 _GLIBCXX_END_NAMESPACE_VERSION
00283 } // namespace
00284 
00285 #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
00286 
00287 #endif // __GXX_EXPERIMENTAL_CXX0X__
00288 
00289 #endif // _GLIBCXX_CONDITION_VARIABLE