libstdc++
concurrence.h
Go to the documentation of this file.
00001 // Support for concurrent programing -*- C++ -*-
00002 
00003 // Copyright (C) 2003-2015 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 ext/concurrence.h
00026  *  This file is a GNU extension to the Standard C++ Library.
00027  */
00028 
00029 #ifndef _CONCURRENCE_H
00030 #define _CONCURRENCE_H 1
00031 
00032 #pragma GCC system_header
00033 
00034 #include <exception>
00035 #include <bits/gthr.h> 
00036 #include <bits/functexcept.h>
00037 #include <bits/cpp_type_traits.h>
00038 #include <ext/type_traits.h>
00039 
00040 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
00041 {
00042 _GLIBCXX_BEGIN_NAMESPACE_VERSION
00043 
00044   // Available locking policies:
00045   // _S_single    single-threaded code that doesn't need to be locked.
00046   // _S_mutex     multi-threaded code that requires additional support
00047   //              from gthr.h or abstraction layers in concurrence.h.
00048   // _S_atomic    multi-threaded code using atomic operations.
00049   enum _Lock_policy { _S_single, _S_mutex, _S_atomic }; 
00050 
00051   // Compile time constant that indicates prefered locking policy in
00052   // the current configuration.
00053   static const _Lock_policy __default_lock_policy = 
00054 #ifdef __GTHREADS
00055 #if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) \
00056      && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4))
00057   _S_atomic;
00058 #else
00059   _S_mutex;
00060 #endif
00061 #else
00062   _S_single;
00063 #endif
00064 
00065   // NB: As this is used in libsupc++, need to only depend on
00066   // exception. No stdexception classes, no use of std::string.
00067   class __concurrence_lock_error : public std::exception
00068   {
00069   public:
00070     virtual char const*
00071     what() const throw()
00072     { return "__gnu_cxx::__concurrence_lock_error"; }
00073   };
00074 
00075   class __concurrence_unlock_error : public std::exception
00076   {
00077   public:
00078     virtual char const*
00079     what() const throw()
00080     { return "__gnu_cxx::__concurrence_unlock_error"; }
00081   };
00082 
00083   class __concurrence_broadcast_error : public std::exception
00084   {
00085   public:
00086     virtual char const*
00087     what() const throw()
00088     { return "__gnu_cxx::__concurrence_broadcast_error"; }
00089   };
00090 
00091   class __concurrence_wait_error : public std::exception
00092   {
00093   public:
00094     virtual char const*
00095     what() const throw()
00096     { return "__gnu_cxx::__concurrence_wait_error"; }
00097   };
00098 
00099   // Substitute for concurrence_error object in the case of -fno-exceptions.
00100   inline void
00101   __throw_concurrence_lock_error()
00102   { _GLIBCXX_THROW_OR_ABORT(__concurrence_lock_error()); }
00103 
00104   inline void
00105   __throw_concurrence_unlock_error()
00106   { _GLIBCXX_THROW_OR_ABORT(__concurrence_unlock_error()); }
00107 
00108 #ifdef __GTHREAD_HAS_COND
00109   inline void
00110   __throw_concurrence_broadcast_error()
00111   { _GLIBCXX_THROW_OR_ABORT(__concurrence_broadcast_error()); }
00112 
00113   inline void
00114   __throw_concurrence_wait_error()
00115   { _GLIBCXX_THROW_OR_ABORT(__concurrence_wait_error()); }
00116 #endif
00117  
00118   class __mutex 
00119   {
00120   private:
00121 #if __GTHREADS && defined __GTHREAD_MUTEX_INIT
00122     __gthread_mutex_t _M_mutex = __GTHREAD_MUTEX_INIT;
00123 #else
00124     __gthread_mutex_t _M_mutex;
00125 #endif
00126 
00127     __mutex(const __mutex&);
00128     __mutex& operator=(const __mutex&);
00129 
00130   public:
00131     __mutex() 
00132     { 
00133 #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT
00134       if (__gthread_active_p())
00135         __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
00136 #endif
00137     }
00138 
00139 #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT
00140     ~__mutex() 
00141     { 
00142       if (__gthread_active_p())
00143         __gthread_mutex_destroy(&_M_mutex); 
00144     }
00145 #endif 
00146 
00147     void lock()
00148     {
00149 #if __GTHREADS
00150       if (__gthread_active_p())
00151         {
00152           if (__gthread_mutex_lock(&_M_mutex) != 0)
00153             __throw_concurrence_lock_error();
00154         }
00155 #endif
00156     }
00157     
00158     void unlock()
00159     {
00160 #if __GTHREADS
00161       if (__gthread_active_p())
00162         {
00163           if (__gthread_mutex_unlock(&_M_mutex) != 0)
00164             __throw_concurrence_unlock_error();
00165         }
00166 #endif
00167     }
00168 
00169     __gthread_mutex_t* gthread_mutex(void)
00170       { return &_M_mutex; }
00171   };
00172 
00173   class __recursive_mutex 
00174   {
00175   private:
00176 #if __GTHREADS && defined __GTHREAD_RECURSIVE_MUTEX_INIT
00177     __gthread_recursive_mutex_t _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT;
00178 #else
00179     __gthread_recursive_mutex_t _M_mutex;
00180 #endif
00181 
00182     __recursive_mutex(const __recursive_mutex&);
00183     __recursive_mutex& operator=(const __recursive_mutex&);
00184 
00185   public:
00186     __recursive_mutex() 
00187     { 
00188 #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT
00189       if (__gthread_active_p())
00190         __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
00191 #endif
00192     }
00193 
00194 #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT
00195     ~__recursive_mutex()
00196     {
00197       if (__gthread_active_p())
00198         __gthread_recursive_mutex_destroy(&_M_mutex);
00199     }
00200 #endif
00201 
00202     void lock()
00203     { 
00204 #if __GTHREADS
00205       if (__gthread_active_p())
00206         {
00207           if (__gthread_recursive_mutex_lock(&_M_mutex) != 0)
00208             __throw_concurrence_lock_error();
00209         }
00210 #endif
00211     }
00212     
00213     void unlock()
00214     { 
00215 #if __GTHREADS
00216       if (__gthread_active_p())
00217         {
00218           if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0)
00219             __throw_concurrence_unlock_error();
00220         }
00221 #endif
00222     }
00223 
00224     __gthread_recursive_mutex_t* gthread_recursive_mutex(void)
00225     { return &_M_mutex; }
00226   };
00227 
00228   /// Scoped lock idiom.
00229   // Acquire the mutex here with a constructor call, then release with
00230   // the destructor call in accordance with RAII style.
00231   class __scoped_lock
00232   {
00233   public:
00234     typedef __mutex __mutex_type;
00235 
00236   private:
00237     __mutex_type& _M_device;
00238 
00239     __scoped_lock(const __scoped_lock&);
00240     __scoped_lock& operator=(const __scoped_lock&);
00241 
00242   public:
00243     explicit __scoped_lock(__mutex_type& __name) : _M_device(__name)
00244     { _M_device.lock(); }
00245 
00246     ~__scoped_lock() throw()
00247     { _M_device.unlock(); }
00248   };
00249 
00250 #ifdef __GTHREAD_HAS_COND
00251   class __cond
00252   {
00253   private:
00254 #if __GTHREADS && defined __GTHREAD_COND_INIT
00255     __gthread_cond_t _M_cond = __GTHREAD_COND_INIT;
00256 #else
00257     __gthread_cond_t _M_cond;
00258 #endif
00259 
00260     __cond(const __cond&);
00261     __cond& operator=(const __cond&);
00262 
00263   public:
00264     __cond() 
00265     { 
00266 #if __GTHREADS && ! defined __GTHREAD_COND_INIT
00267       if (__gthread_active_p())
00268         __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
00269 #endif
00270     }
00271 
00272 #if __GTHREADS && ! defined __GTHREAD_COND_INIT
00273     ~__cond() 
00274     { 
00275       if (__gthread_active_p())
00276         __gthread_cond_destroy(&_M_cond); 
00277     }
00278 #endif 
00279 
00280     void broadcast()
00281     {
00282 #if __GTHREADS
00283       if (__gthread_active_p())
00284         {
00285           if (__gthread_cond_broadcast(&_M_cond) != 0)
00286             __throw_concurrence_broadcast_error();
00287         }
00288 #endif
00289     }
00290 
00291     void wait(__mutex *mutex)
00292     {
00293 #if __GTHREADS
00294       {
00295           if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0)
00296             __throw_concurrence_wait_error();
00297       }
00298 #endif
00299     }
00300 
00301     void wait_recursive(__recursive_mutex *mutex)
00302     {
00303 #if __GTHREADS
00304       {
00305           if (__gthread_cond_wait_recursive(&_M_cond,
00306                                             mutex->gthread_recursive_mutex())
00307               != 0)
00308             __throw_concurrence_wait_error();
00309       }
00310 #endif
00311     }
00312   };
00313 #endif
00314 
00315 _GLIBCXX_END_NAMESPACE_VERSION
00316 } // namespace
00317 
00318 #endif