libstdc++
condition_variable
Go to the documentation of this file.
00001 // <condition_variable> -*- C++ -*-
00002 
00003 // Copyright (C) 2008, 2009, 2010 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   public:
00180 
00181     condition_variable_any() noexcept;
00182     ~condition_variable_any() noexcept;
00183 
00184     condition_variable_any(const condition_variable_any&) = delete;
00185     condition_variable_any& operator=(const condition_variable_any&) = delete;
00186 
00187     void
00188     notify_one() noexcept
00189     {
00190       lock_guard<mutex> __lock(_M_mutex);
00191       _M_cond.notify_one();
00192     }
00193 
00194     void
00195     notify_all() noexcept
00196     {
00197       lock_guard<mutex> __lock(_M_mutex);
00198       _M_cond.notify_all();
00199     }
00200 
00201     template<typename _Lock>
00202       void
00203       wait(_Lock& __lock)
00204       {
00205     // scoped unlock - unlocks in ctor, re-locks in dtor
00206     struct _Unlock {
00207       explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); }
00208       ~_Unlock() noexcept(false)
00209       {
00210         if (uncaught_exception())
00211           __try { _M_lock.lock(); } __catch(...) { }
00212         else
00213           _M_lock.lock();
00214       }
00215       _Lock& _M_lock;
00216     };
00217 
00218     unique_lock<mutex> __my_lock(_M_mutex);
00219     _Unlock __unlock(__lock);
00220     // _M_mutex must be unlocked before re-locking __lock so move
00221     // ownership of _M_mutex lock to an object with shorter lifetime.
00222     unique_lock<mutex> __my_lock2(std::move(__my_lock));
00223     _M_cond.wait(__my_lock2);
00224       }
00225       
00226 
00227     template<typename _Lock, typename _Predicate>
00228       void
00229       wait(_Lock& __lock, _Predicate __p)
00230       {
00231     while (!__p())
00232       wait(__lock);
00233       }
00234 
00235     template<typename _Lock, typename _Clock, typename _Duration>
00236       cv_status
00237       wait_until(_Lock& __lock,
00238          const chrono::time_point<_Clock, _Duration>& __atime)
00239       {
00240         unique_lock<mutex> __my_lock(_M_mutex);
00241         __lock.unlock();
00242         cv_status __status = _M_cond.wait_until(__my_lock, __atime);
00243         __lock.lock();
00244         return __status;
00245       }
00246 
00247     template<typename _Lock, typename _Clock,
00248          typename _Duration, typename _Predicate>
00249       bool
00250       wait_until(_Lock& __lock,
00251          const chrono::time_point<_Clock, _Duration>& __atime,
00252          _Predicate __p)
00253       {
00254     while (!__p())
00255       if (wait_until(__lock, __atime) == cv_status::timeout)
00256         return __p();
00257     return true;
00258       }
00259 
00260     template<typename _Lock, typename _Rep, typename _Period>
00261       cv_status
00262       wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __rtime)
00263       { return wait_until(__lock, __clock_t::now() + __rtime); }
00264 
00265     template<typename _Lock, typename _Rep,
00266          typename _Period, typename _Predicate>
00267       bool
00268       wait_for(_Lock& __lock,
00269            const chrono::duration<_Rep, _Period>& __rtime, _Predicate __p)
00270       { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); }
00271   };
00272 
00273   // @} group condition_variables
00274 _GLIBCXX_END_NAMESPACE_VERSION
00275 } // namespace
00276 
00277 #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
00278 
00279 #endif // __GXX_EXPERIMENTAL_CXX0X__
00280 
00281 #endif // _GLIBCXX_CONDITION_VARIABLE