# concurrence.h

Go to the documentation of this file.

    00001 // Support for concurrent programing -*- C++ -*-
    00002
    00003 // Copyright (C) 2003, 2004, 2005, 2006
    00004 // Free Software Foundation, Inc.
    00005 //
    00006 // This file is part of the GNU ISO C++ Library.  This library is free
    00007 // software; you can redistribute it and/or modify it under the
    00008 // terms of the GNU General Public License as published by the
    00009 // Free Software Foundation; either version 2, or (at your option)
    00010 // any later version.
    00011
    00012 // This library is distributed in the hope that it will be useful,
    00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
    00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00015 // GNU General Public License for more details.
    00016
    00017 // You should have received a copy of the GNU General Public License along
    00018 // with this library; see the file COPYING.  If not, write to the Free
    00019 // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
    00020 // USA.
    00021
    00022 // As a special exception, you may use this file as part of a free software
    00023 // library without restriction.  Specifically, if other files instantiate
    00024 // templates or use macros or inline functions from this file, or you compile
    00025 // this file and link it with other files to produce an executable, this
    00026 // file does not by itself cause the resulting executable to be covered by
    00027 // the GNU General Public License.  This exception does not however
    00028 // invalidate any other reasons why the executable file might be covered by
    00029 // the GNU General Public License.
    00030
    00031 /** @file concurrence.h
    00032  *  This is an internal header file, included by other library headers.
    00033  *  You should not attempt to use it directly.
    00034  */
    00035
    00036 #ifndef _CONCURRENCE_H
    00037 #define _CONCURRENCE_H 1
    00038
    00039 #include <cstdlib>
    00040 #include <exception>
    00041 #include <bits/gthr.h>
    00042 #include <bits/functexcept.h>
    00043
    00044 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
    00045
    00046   // Available locking policies:
    00047   // _S_single    single-threaded code that doesn't need to be locked.
    00048   // _S_mutex     multi-threaded code that requires additional support
    00049   //              from gthr.h or abstraction layers in concurrence.h.
    00050   // _S_atomic    multi-threaded code using atomic operations.
    00051   enum _Lock_policy { _S_single, _S_mutex, _S_atomic };
    00052
    00053   // Compile time constant that indicates prefered locking policy in
    00054   // the current configuration.
    00055   static const _Lock_policy __default_lock_policy =
    00056 #ifdef __GTHREADS
    00057   // NB: This macro doesn't actually exist yet in the compiler, but is
    00058   // set somewhat haphazardly at configure time.
    00059 #ifdef _GLIBCXX_ATOMIC_BUILTINS
    00060   _S_atomic;
    00061 #else
    00062   _S_mutex;
    00063 #endif
    00064 #else
    00065   _S_single;
    00066 #endif
    00067
    00068   // NB: As this is used in libsupc++, need to only depend on
    00069   // exception. No stdexception classes, no use of std::string.
    00070   class __concurrence_lock_error : public std::exception
    00071   {
    00072   public:
    00073     virtual char const*
    00074     what() const throw()
    00075     { return "__gnu_cxx::__concurrence_lock_error"; }
    00076   };
    00077
    00078   class __concurrence_unlock_error : public std::exception
    00079   {
    00080   public:
    00081     virtual char const*
    00082     what() const throw()
    00083     { return "__gnu_cxx::__concurrence_unlock_error"; }
    00084   };
    00085
    00086   // Substitute for concurrence_error object in the case of -fno-exceptions.
    00087   inline void
    00088   __throw_concurrence_lock_error()
    00089   {
    00090 #if __EXCEPTIONS
    00091     throw __concurrence_lock_error();
    00092 #else
    00093     std::abort();
    00094 #endif
    00095   }
    00096
    00097   inline void
    00098   __throw_concurrence_unlock_error()
    00099   {
    00100 #if __EXCEPTIONS
    00101     throw __concurrence_unlock_error();
    00102 #else
    00103     std::abort();
    00104 #endif
    00105   }
    00106
    00107   class __mutex
    00108   {
    00109   private:
    00110     __gthread_mutex_t _M_mutex;
    00111
    00112     __mutex(const __mutex&);
    00113     __mutex& operator=(const __mutex&);
    00114
    00115   public:
    00116     __mutex()
    00117     {
    00118 #if __GTHREADS
    00119       if (__gthread_active_p())
    00120     {
    00121 #if defined __GTHREAD_MUTEX_INIT
    00122       __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
    00123       _M_mutex = __tmp;
    00124 #else
    00125       __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
    00126 #endif
    00127     }
    00128 #endif
    00129     }
    00130
    00131     void lock()
    00132     {
    00133 #if __GTHREADS
    00134       if (__gthread_active_p())
    00135     {
    00136       if (__gthread_mutex_lock(&_M_mutex) != 0)
    00137         __throw_concurrence_lock_error();
    00138     }
    00139 #endif
    00140     }
    00141
    00142     void unlock()
    00143     {
    00144 #if __GTHREADS
    00145       if (__gthread_active_p())
    00146     {
    00147       if (__gthread_mutex_unlock(&_M_mutex) != 0)
    00148         __throw_concurrence_unlock_error();
    00149     }
    00150 #endif
    00151     }
    00152   };
    00153
    00154   class __recursive_mutex
    00155   {
    00156   private:
    00157     __gthread_recursive_mutex_t _M_mutex;
    00158
    00159     __recursive_mutex(const __recursive_mutex&);
    00160     __recursive_mutex& operator=(const __recursive_mutex&);
    00161
    00162   public:
    00163     __recursive_mutex()
    00164     {
    00165 #if __GTHREADS
    00166       if (__gthread_active_p())
    00167     {
    00168 #if defined __GTHREAD_RECURSIVE_MUTEX_INIT
    00169       __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT;
    00170       _M_mutex = __tmp;
    00171 #else
    00172       __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
    00173 #endif
    00174     }
    00175 #endif
    00176     }
    00177
    00178     void lock()
    00179     {
    00180 #if __GTHREADS
    00181       if (__gthread_active_p())
    00182     {
    00183       if (__gthread_recursive_mutex_lock(&_M_mutex) != 0)
    00184         __throw_concurrence_lock_error();
    00185     }
    00186 #endif
    00187     }
    00188
    00189     void unlock()
    00190     {
    00191 #if __GTHREADS
    00192       if (__gthread_active_p())
    00193     {
    00194       if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0)
    00195         __throw_concurrence_unlock_error();
    00196     }
    00197 #endif
    00198     }
    00199   };
    00200
    00201   /// @brief  Scoped lock idiom.
    00202   // Acquire the mutex here with a constructor call, then release with
    00203   // the destructor call in accordance with RAII style.
    00204   class __scoped_lock
    00205   {
    00206   public:
    00207     typedef __mutex __mutex_type;
    00208
    00209   private:
    00210     __mutex_type& _M_device;
    00211
    00212     __scoped_lock(const __scoped_lock&);
    00213     __scoped_lock& operator=(const __scoped_lock&);
    00214
    00215   public:
    00216     explicit __scoped_lock(__mutex_type& __name) : _M_device(__name)
    00217     { _M_device.lock(); }
    00218
    00219     ~__scoped_lock() throw()
    00220     { _M_device.unlock(); }
    00221   };
    00222
    00223 _GLIBCXX_END_NAMESPACE
    00224
    00225 #endif