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 #ifdef _GLIBCXX_DTS2_CONDITION_VARIABLE_ANY
00041 # include <memory>
00042 #endif
00043 
00044 #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
00045 
00046 namespace std _GLIBCXX_VISIBILITY(default)
00047 {
00048 _GLIBCXX_BEGIN_NAMESPACE_VERSION
00049 
00050   /**
00051    * @defgroup condition_variables Condition Variables
00052    * @ingroup concurrency
00053    *
00054    * Classes for condition_variable support.
00055    * @{
00056    */
00057 
00058   /// cv_status
00059   enum class cv_status { no_timeout, timeout };
00060   
00061   /// condition_variable
00062   class condition_variable
00063   {
00064     typedef chrono::system_clock    __clock_t;
00065     typedef __gthread_cond_t        __native_type;
00066 
00067 #ifdef __GTHREAD_COND_INIT
00068     __native_type           _M_cond = __GTHREAD_COND_INIT;
00069 #else
00070     __native_type           _M_cond;
00071 #endif
00072 
00073   public:
00074     typedef __native_type*      native_handle_type;
00075 
00076     condition_variable() noexcept;
00077     ~condition_variable() noexcept;
00078 
00079     condition_variable(const condition_variable&) = delete;
00080     condition_variable& operator=(const condition_variable&) = delete;
00081 
00082     void
00083     notify_one() noexcept;
00084 
00085     void
00086     notify_all() noexcept;
00087 
00088     void
00089     wait(unique_lock<mutex>& __lock);
00090 
00091     template<typename _Predicate>
00092       void
00093       wait(unique_lock<mutex>& __lock, _Predicate __p)
00094       {
00095     while (!__p())
00096       wait(__lock);
00097       }
00098 
00099     template<typename _Duration>
00100       cv_status
00101       wait_until(unique_lock<mutex>& __lock,
00102          const chrono::time_point<__clock_t, _Duration>& __atime)
00103       { return __wait_until_impl(__lock, __atime); }
00104 
00105     template<typename _Clock, typename _Duration>
00106       cv_status
00107       wait_until(unique_lock<mutex>& __lock,
00108          const chrono::time_point<_Clock, _Duration>& __atime)
00109       {
00110     // DR 887 - Sync unknown clock to known clock.
00111     const typename _Clock::time_point __c_entry = _Clock::now();
00112     const __clock_t::time_point __s_entry = __clock_t::now();
00113     const auto __delta = __atime - __c_entry;
00114     const auto __s_atime = __s_entry + __delta;
00115 
00116     return __wait_until_impl(__lock, __s_atime);
00117       }
00118 
00119     template<typename _Clock, typename _Duration, typename _Predicate>
00120       bool
00121       wait_until(unique_lock<mutex>& __lock,
00122          const chrono::time_point<_Clock, _Duration>& __atime,
00123          _Predicate __p)
00124       {
00125     while (!__p())
00126       if (wait_until(__lock, __atime) == cv_status::timeout)
00127         return __p();
00128     return true;
00129       }
00130 
00131     template<typename _Rep, typename _Period>
00132       cv_status
00133       wait_for(unique_lock<mutex>& __lock,
00134            const chrono::duration<_Rep, _Period>& __rtime)
00135       { return wait_until(__lock, __clock_t::now() + __rtime); }
00136 
00137     template<typename _Rep, typename _Period, typename _Predicate>
00138       bool
00139       wait_for(unique_lock<mutex>& __lock,
00140            const chrono::duration<_Rep, _Period>& __rtime,
00141            _Predicate __p)
00142       { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); }
00143 
00144     native_handle_type
00145     native_handle()
00146     { return &_M_cond; }
00147 
00148   private:
00149     template<typename _Dur>
00150       cv_status
00151       __wait_until_impl(unique_lock<mutex>& __lock,
00152             const chrono::time_point<__clock_t, _Dur>& __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       {
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_t::now() < __atime
00167         ? cv_status::no_timeout : cv_status::timeout);
00168       }
00169   };
00170 
00171 #ifdef _GLIBCXX_DTS2_CONDITION_VARIABLE_ANY
00172   inline namespace _V2 {
00173 #endif
00174 
00175   /// condition_variable_any
00176   // Like above, but mutex is not required to have try_lock.
00177   class condition_variable_any
00178   {
00179     typedef chrono::system_clock    __clock_t;
00180     condition_variable          _M_cond;
00181 #ifdef _GLIBCXX_DTS2_CONDITION_VARIABLE_ANY
00182     shared_ptr<mutex>           _M_mutex;
00183 #else
00184     mutex               _M_mutex;
00185 #endif
00186 
00187     // scoped unlock - unlocks in ctor, re-locks in dtor
00188     template<typename _Lock>
00189       struct _Unlock
00190       {
00191     explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); }
00192 
00193     ~_Unlock() noexcept(false)
00194     {
00195       if (uncaught_exception())
00196         __try { _M_lock.lock(); } __catch(...) { }
00197       else
00198         _M_lock.lock();
00199     }
00200 
00201     _Unlock(const _Unlock&) = delete;
00202     _Unlock& operator=(const _Unlock&) = delete;
00203 
00204     _Lock& _M_lock;
00205       };
00206 
00207   public:
00208 #ifdef _GLIBCXX_DTS2_CONDITION_VARIABLE_ANY
00209     condition_variable_any() : _M_mutex(std::make_shared<mutex>()) { }
00210     ~condition_variable_any() = default;
00211 #else
00212     condition_variable_any() noexcept;
00213     ~condition_variable_any() noexcept;
00214 #endif
00215 
00216     condition_variable_any(const condition_variable_any&) = delete;
00217     condition_variable_any& operator=(const condition_variable_any&) = delete;
00218 
00219     void
00220     notify_one() noexcept
00221     {
00222 #ifdef _GLIBCXX_DTS2_CONDITION_VARIABLE_ANY
00223       lock_guard<mutex> __lock(*_M_mutex);
00224 #else
00225       lock_guard<mutex> __lock(_M_mutex);
00226 #endif
00227       _M_cond.notify_one();
00228     }
00229 
00230     void
00231     notify_all() noexcept
00232     {
00233 #ifdef _GLIBCXX_DTS2_CONDITION_VARIABLE_ANY
00234       lock_guard<mutex> __lock(*_M_mutex);
00235 #else
00236       lock_guard<mutex> __lock(_M_mutex);
00237 #endif
00238       _M_cond.notify_all();
00239     }
00240 
00241     template<typename _Lock>
00242       void
00243       wait(_Lock& __lock)
00244       {
00245 #ifdef _GLIBCXX_DTS2_CONDITION_VARIABLE_ANY
00246     shared_ptr<mutex> __mutex = _M_mutex;
00247     unique_lock<mutex> __my_lock(*__mutex);
00248 #else
00249     unique_lock<mutex> __my_lock(_M_mutex);
00250 #endif
00251     _Unlock<_Lock> __unlock(__lock);
00252     // _M_mutex must be unlocked before re-locking __lock so move
00253     // ownership of _M_mutex lock to an object with shorter lifetime.
00254     unique_lock<mutex> __my_lock2(std::move(__my_lock));
00255     _M_cond.wait(__my_lock2);
00256       }
00257       
00258 
00259     template<typename _Lock, typename _Predicate>
00260       void
00261       wait(_Lock& __lock, _Predicate __p)
00262       {
00263     while (!__p())
00264       wait(__lock);
00265       }
00266 
00267     template<typename _Lock, typename _Clock, typename _Duration>
00268       cv_status
00269       wait_until(_Lock& __lock,
00270          const chrono::time_point<_Clock, _Duration>& __atime)
00271       {
00272 #ifdef _GLIBCXX_DTS2_CONDITION_VARIABLE_ANY
00273     shared_ptr<mutex> __mutex = _M_mutex;
00274     unique_lock<mutex> __my_lock(*__mutex);
00275 #else
00276     unique_lock<mutex> __my_lock(_M_mutex);
00277 #endif
00278     _Unlock<_Lock> __unlock(__lock);
00279     // _M_mutex must be unlocked before re-locking __lock so move
00280     // ownership of _M_mutex lock to an object with shorter lifetime.
00281     unique_lock<mutex> __my_lock2(std::move(__my_lock));
00282     return _M_cond.wait_until(__my_lock2, __atime);
00283       }
00284 
00285     template<typename _Lock, typename _Clock,
00286          typename _Duration, typename _Predicate>
00287       bool
00288       wait_until(_Lock& __lock,
00289          const chrono::time_point<_Clock, _Duration>& __atime,
00290          _Predicate __p)
00291       {
00292     while (!__p())
00293       if (wait_until(__lock, __atime) == cv_status::timeout)
00294         return __p();
00295     return true;
00296       }
00297 
00298     template<typename _Lock, typename _Rep, typename _Period>
00299       cv_status
00300       wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __rtime)
00301       { return wait_until(__lock, __clock_t::now() + __rtime); }
00302 
00303     template<typename _Lock, typename _Rep,
00304          typename _Period, typename _Predicate>
00305       bool
00306       wait_for(_Lock& __lock,
00307            const chrono::duration<_Rep, _Period>& __rtime, _Predicate __p)
00308       { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); }
00309   };
00310 
00311 #ifdef _GLIBCXX_DTS2_CONDITION_VARIABLE_ANY
00312   } // end inline namespace
00313 #endif
00314 
00315   // @} group condition_variables
00316 _GLIBCXX_END_NAMESPACE_VERSION
00317 } // namespace
00318 
00319 #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
00320 
00321 #endif // C++11
00322 
00323 #endif // _GLIBCXX_CONDITION_VARIABLE