# mutex

Go to the documentation of this file.

    00001 // <mutex> -*- C++ -*-
    00002
    00003 // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
    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 3, 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 // Under Section 7 of GPL version 3, you are granted additional
    00018 // permissions described in the GCC Runtime Library Exception, version
    00019 // 3.1, as published by the Free Software Foundation.
    00020
    00021 // You should have received a copy of the GNU General Public License and
    00022 // a copy of the GCC Runtime Library Exception along with this program;
    00023 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
    00024 // <http://www.gnu.org/licenses/>.
    00025
    00026 /** @file mutex
    00027  *  This is a Standard C++ Library header.
    00028  */
    00029
    00030 #ifndef _GLIBCXX_MUTEX
    00031 #define _GLIBCXX_MUTEX 1
    00032
    00033 #pragma GCC system_header
    00034
    00035 #ifndef __GXX_EXPERIMENTAL_CXX0X__
    00036 # include <c++0x_warning.h>
    00037 #else
    00038
    00039 #include <tuple>
    00040 #include <cstddef>
    00041 #include <chrono>
    00042 #include <exception>
    00043 #include <type_traits>
    00044 #include <functional>
    00045 #include <system_error>
    00046 #include <bits/functexcept.h>
    00047 #include <bits/gthr.h>
    00048 #include <bits/move.h> // for std::swap
    00049
    00050 #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
    00051
    00052 namespace std
    00053 {
    00054   /**
    00055    * @defgroup mutexes Mutexes
    00056    * @ingroup concurrency
    00057    *
    00058    * Classes for mutex support.
    00059    * @{
    00060    */
    00061
    00062   /// mutex
    00063   class mutex
    00064   {
    00065     typedef __gthread_mutex_t           __native_type;
    00066     __native_type  _M_mutex;
    00067
    00068   public:
    00069     typedef __native_type*          native_handle_type;
    00070
    00071     mutex()
    00072     {
    00073       // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
    00074 #ifdef __GTHREAD_MUTEX_INIT
    00075       __native_type __tmp = __GTHREAD_MUTEX_INIT;
    00076       _M_mutex = __tmp;
    00077 #else
    00078       __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
    00079 #endif
    00080     }
    00081
    00082     mutex(const mutex&) = delete;
    00083     mutex& operator=(const mutex&) = delete;
    00084
    00085     void
    00086     lock()
    00087     {
    00088       int __e = __gthread_mutex_lock(&_M_mutex);
    00089
    00090       // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
    00091       if (__e)
    00092     __throw_system_error(__e);
    00093     }
    00094
    00095     bool
    00096     try_lock()
    00097     {
    00098       // XXX EINVAL, EAGAIN, EBUSY
    00099       return !__gthread_mutex_trylock(&_M_mutex);
    00100     }
    00101
    00102     void
    00103     unlock()
    00104     {
    00105       // XXX EINVAL, EAGAIN, EPERM
    00106       __gthread_mutex_unlock(&_M_mutex);
    00107     }
    00108
    00109     native_handle_type
    00110     native_handle()
    00111     { return &_M_mutex; }
    00112   };
    00113
    00114   /// recursive_mutex
    00115   class recursive_mutex
    00116   {
    00117     typedef __gthread_recursive_mutex_t     __native_type;
    00118     __native_type  _M_mutex;
    00119
    00120   public:
    00121     typedef __native_type*          native_handle_type;
    00122
    00123     recursive_mutex()
    00124     {
    00125       // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
    00126 #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT
    00127       __native_type __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT;
    00128       _M_mutex = __tmp;
    00129 #else
    00130       __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
    00131 #endif
    00132     }
    00133
    00134     recursive_mutex(const recursive_mutex&) = delete;
    00135     recursive_mutex& operator=(const recursive_mutex&) = delete;
    00136
    00137     void
    00138     lock()
    00139     {
    00140       int __e = __gthread_recursive_mutex_lock(&_M_mutex);
    00141
    00142       // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
    00143       if (__e)
    00144     __throw_system_error(__e);
    00145     }
    00146
    00147     bool
    00148     try_lock()
    00149     {
    00150       // XXX EINVAL, EAGAIN, EBUSY
    00151       return !__gthread_recursive_mutex_trylock(&_M_mutex);
    00152     }
    00153
    00154     void
    00155     unlock()
    00156     {
    00157       // XXX EINVAL, EAGAIN, EBUSY
    00158       __gthread_recursive_mutex_unlock(&_M_mutex);
    00159     }
    00160
    00161     native_handle_type
    00162     native_handle()
    00163     { return &_M_mutex; }
    00164   };
    00165
    00166   /// timed_mutex
    00167   class timed_mutex
    00168   {
    00169     typedef __gthread_mutex_t           __native_type;
    00170
    00171 #ifdef _GLIBCXX_USE_CLOCK_MONOTONIC
    00172     typedef chrono::monotonic_clock         __clock_t;
    00173 #else
    00174     typedef chrono::high_resolution_clock   __clock_t;
    00175 #endif
    00176
    00177     __native_type  _M_mutex;
    00178
    00179   public:
    00180     typedef __native_type*          native_handle_type;
    00181
    00182     timed_mutex()
    00183     {
    00184 #ifdef __GTHREAD_MUTEX_INIT
    00185       __native_type __tmp = __GTHREAD_MUTEX_INIT;
    00186       _M_mutex = __tmp;
    00187 #else
    00188       __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
    00189 #endif
    00190     }
    00191
    00192     timed_mutex(const timed_mutex&) = delete;
    00193     timed_mutex& operator=(const timed_mutex&) = delete;
    00194
    00195     void
    00196     lock()
    00197     {
    00198       int __e = __gthread_mutex_lock(&_M_mutex);
    00199
    00200       // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
    00201       if (__e)
    00202     __throw_system_error(__e);
    00203     }
    00204
    00205     bool
    00206     try_lock()
    00207     {
    00208       // XXX EINVAL, EAGAIN, EBUSY
    00209       return !__gthread_mutex_trylock(&_M_mutex);
    00210     }
    00211
    00212     template <class _Rep, class _Period>
    00213       bool
    00214       try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
    00215       { return __try_lock_for_impl(__rtime); }
    00216
    00217     template <class _Clock, class _Duration>
    00218       bool
    00219       try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
    00220       {
    00221     chrono::time_point<_Clock, chrono::seconds> __s =
    00222       chrono::time_point_cast<chrono::seconds>(__atime);
    00223
    00224     chrono::nanoseconds __ns =
    00225       chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
    00226
    00227     __gthread_time_t __ts = {
    00228       static_cast<std::time_t>(__s.time_since_epoch().count()),
    00229       static_cast<long>(__ns.count())
    00230     };
    00231
    00232     return !__gthread_mutex_timedlock(&_M_mutex, &__ts);
    00233       }
    00234
    00235     void
    00236     unlock()
    00237     {
    00238       // XXX EINVAL, EAGAIN, EBUSY
    00239       __gthread_mutex_unlock(&_M_mutex);
    00240     }
    00241
    00242     native_handle_type
    00243     native_handle()
    00244     { return &_M_mutex; }
    00245
    00246   private:
    00247     template<typename _Rep, typename _Period>
    00248       typename enable_if<
    00249     ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
    00250       __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
    00251       {
    00252     __clock_t::time_point __atime = __clock_t::now()
    00253       + chrono::duration_cast<__clock_t::duration>(__rtime);
    00254
    00255     return try_lock_until(__atime);
    00256       }
    00257
    00258     template <typename _Rep, typename _Period>
    00259       typename enable_if<
    00260     !ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
    00261       __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
    00262       {
    00263     __clock_t::time_point __atime = __clock_t::now()
    00264       + ++chrono::duration_cast<__clock_t::duration>(__rtime);
    00265
    00266     return try_lock_until(__atime);
    00267       }
    00268   };
    00269
    00270   /// recursive_timed_mutex
    00271   class recursive_timed_mutex
    00272   {
    00273     typedef __gthread_recursive_mutex_t     __native_type;
    00274
    00275 #ifdef _GLIBCXX_USE_CLOCK_MONOTONIC
    00276     typedef chrono::monotonic_clock         __clock_t;
    00277 #else
    00278     typedef chrono::high_resolution_clock   __clock_t;
    00279 #endif
    00280
    00281     __native_type  _M_mutex;
    00282
    00283   public:
    00284     typedef __native_type*          native_handle_type;
    00285
    00286     recursive_timed_mutex()
    00287     {
    00288       // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
    00289 #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT
    00290       __native_type __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT;
    00291       _M_mutex = __tmp;
    00292 #else
    00293       __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
    00294 #endif
    00295     }
    00296
    00297     recursive_timed_mutex(const recursive_timed_mutex&) = delete;
    00298     recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
    00299
    00300     void
    00301     lock()
    00302     {
    00303       int __e = __gthread_recursive_mutex_lock(&_M_mutex);
    00304
    00305       // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
    00306       if (__e)
    00307     __throw_system_error(__e);
    00308     }
    00309
    00310     bool
    00311     try_lock()
    00312     {
    00313       // XXX EINVAL, EAGAIN, EBUSY
    00314       return !__gthread_recursive_mutex_trylock(&_M_mutex);
    00315     }
    00316
    00317     template <class _Rep, class _Period>
    00318       bool
    00319       try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
    00320       { return __try_lock_for_impl(__rtime); }
    00321
    00322     template <class _Clock, class _Duration>
    00323       bool
    00324       try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
    00325       {
    00326     chrono::time_point<_Clock, chrono::seconds>  __s =
    00327       chrono::time_point_cast<chrono::seconds>(__atime);
    00328
    00329     chrono::nanoseconds __ns =
    00330       chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
    00331
    00332     __gthread_time_t __ts = {
    00333       static_cast<std::time_t>(__s.time_since_epoch().count()),
    00334       static_cast<long>(__ns.count())
    00335     };
    00336
    00337     return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts);
    00338       }
    00339
    00340     void
    00341     unlock()
    00342     {
    00343       // XXX EINVAL, EAGAIN, EBUSY
    00344       __gthread_recursive_mutex_unlock(&_M_mutex);
    00345     }
    00346
    00347     native_handle_type
    00348     native_handle()
    00349     { return &_M_mutex; }
    00350
    00351   private:
    00352     template<typename _Rep, typename _Period>
    00353       typename enable_if<
    00354     ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
    00355       __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
    00356       {
    00357     __clock_t::time_point __atime = __clock_t::now()
    00358       + chrono::duration_cast<__clock_t::duration>(__rtime);
    00359
    00360     return try_lock_until(__atime);
    00361       }
    00362
    00363     template <typename _Rep, typename _Period>
    00364       typename enable_if<
    00365     !ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
    00366       __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
    00367       {
    00368     __clock_t::time_point __atime = __clock_t::now()
    00369       + ++chrono::duration_cast<__clock_t::duration>(__rtime);
    00370
    00371     return try_lock_until(__atime);
    00372       }
    00373   };
    00374
    00375   /// Do not acquire ownership of the mutex.
    00376   struct defer_lock_t { };
    00377
    00378   /// Try to acquire ownership of the mutex without blocking.
    00379   struct try_to_lock_t { };
    00380
    00381   /// Assume the calling thread has already obtained mutex ownership
    00382   /// and manage it.
    00383   struct adopt_lock_t { };
    00384
    00385   extern const defer_lock_t defer_lock;
    00386   extern const try_to_lock_t    try_to_lock;
    00387   extern const adopt_lock_t adopt_lock;
    00388
    00389   /**
    00390    *  @brief Thrown to indicate errors with lock operations.
    00391    *
    00392    *  @ingroup exceptions
    00393    */
    00394   class lock_error : public exception
    00395   {
    00396   public:
    00397     virtual const char*
    00398     what() const throw();
    00399   };
    00400
    00401   /// @brief  Scoped lock idiom.
    00402   // Acquire the mutex here with a constructor call, then release with
    00403   // the destructor call in accordance with RAII style.
    00404   template<typename _Mutex>
    00405     class lock_guard
    00406     {
    00407     public:
    00408       typedef _Mutex mutex_type;
    00409
    00410       explicit lock_guard(mutex_type& __m) : _M_device(__m)
    00411       { _M_device.lock(); }
    00412
    00413       lock_guard(mutex_type& __m, adopt_lock_t __a) : _M_device(__m)
    00414       { _M_device.lock(); }
    00415
    00416       ~lock_guard()
    00417       { _M_device.unlock(); }
    00418
    00419       lock_guard(const lock_guard&) = delete;
    00420       lock_guard& operator=(const lock_guard&) = delete;
    00421
    00422     private:
    00423       mutex_type&  _M_device;
    00424     };
    00425
    00426   /// unique_lock
    00427   template<typename _Mutex>
    00428     class unique_lock
    00429     {
    00430     public:
    00431       typedef _Mutex mutex_type;
    00432
    00433       unique_lock()
    00434       : _M_device(0), _M_owns(false)
    00435       { }
    00436
    00437       explicit unique_lock(mutex_type& __m)
    00438       : _M_device(&__m), _M_owns(false)
    00439       {
    00440     lock();
    00441     _M_owns = true;
    00442       }
    00443
    00444       unique_lock(mutex_type& __m, defer_lock_t)
    00445       : _M_device(&__m), _M_owns(false)
    00446       { }
    00447
    00448       unique_lock(mutex_type& __m, try_to_lock_t)
    00449       : _M_device(&__m), _M_owns(_M_device->try_lock())
    00450       { }
    00451
    00452       unique_lock(mutex_type& __m, adopt_lock_t)
    00453       : _M_device(&__m), _M_owns(true)
    00454       {
    00455     // XXX calling thread owns mutex
    00456       }
    00457
    00458       template<typename _Clock, typename _Duration>
    00459     unique_lock(mutex_type& __m,
    00460             const chrono::time_point<_Clock, _Duration>& __atime)
    00461     : _M_device(&__m), _M_owns(_M_device->try_lock_until(__atime))
    00462     { }
    00463
    00464       template<typename _Rep, typename _Period>
    00465     unique_lock(mutex_type& __m,
    00466             const chrono::duration<_Rep, _Period>& __rtime)
    00467     : _M_device(&__m), _M_owns(_M_device->try_lock_for(__rtime))
    00468     { }
    00469
    00470       ~unique_lock()
    00471       {
    00472     if (_M_owns)
    00473       unlock();
    00474       }
    00475
    00476       unique_lock(const unique_lock&) = delete;
    00477       unique_lock& operator=(const unique_lock&) = delete;
    00478
    00479       unique_lock(unique_lock&& __u)
    00480       : _M_device(__u._M_device), _M_owns(__u._M_owns)
    00481       {
    00482     __u._M_device = 0;
    00483     __u._M_owns = false;
    00484       }
    00485
    00486       unique_lock& operator=(unique_lock&& __u)
    00487       {
    00488     if(_M_owns)
    00489       unlock();
    00490
    00491     unique_lock(std::move(__u)).swap(*this);
    00492
    00493     __u._M_device = 0;
    00494     __u._M_owns = false;
    00495
    00496     return *this;
    00497       }
    00498
    00499       void
    00500       lock()
    00501       {
    00502     if (!_M_device)
    00503       __throw_system_error(int(errc::operation_not_permitted));
    00504     else if (_M_owns)
    00505       __throw_system_error(int(errc::resource_deadlock_would_occur));
    00506     else
    00507       {
    00508         _M_device->lock();
    00509         _M_owns = true;
    00510       }
    00511       }
    00512
    00513       bool
    00514       try_lock()
    00515       {
    00516     if (!_M_device)
    00517       __throw_system_error(int(errc::operation_not_permitted));
    00518     else if (_M_owns)
    00519       __throw_system_error(int(errc::resource_deadlock_would_occur));
    00520     else
    00521       {
    00522         _M_owns = _M_device->try_lock();
    00523         return _M_owns;
    00524       }
    00525       }
    00526
    00527       template<typename _Clock, typename _Duration>
    00528     bool
    00529     try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
    00530     {
    00531       if (!_M_device)
    00532         __throw_system_error(int(errc::operation_not_permitted));
    00533       else if (_M_owns)
    00534         __throw_system_error(int(errc::resource_deadlock_would_occur));
    00535       else
    00536         {
    00537           _M_owns = _M_device->try_lock_until(__atime);
    00538           return _M_owns;
    00539         }
    00540     }
    00541
    00542       template<typename _Rep, typename _Period>
    00543     bool
    00544     try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
    00545     {
    00546       if (!_M_device)
    00547         __throw_system_error(int(errc::operation_not_permitted));
    00548       else if (_M_owns)
    00549         __throw_system_error(int(errc::resource_deadlock_would_occur));
    00550       else
    00551         {
    00552           _M_owns = _M_device->try_lock_for(__rtime);
    00553           return _M_owns;
    00554         }
    00555      }
    00556
    00557       void
    00558       unlock()
    00559       {
    00560     if (!_M_owns)
    00561       __throw_system_error(int(errc::operation_not_permitted));
    00562     else if (_M_device)
    00563       {
    00564         _M_device->unlock();
    00565         _M_owns = false;
    00566       }
    00567       }
    00568
    00569       void
    00570       swap(unique_lock&& __u)
    00571       {
    00572     std::swap(_M_device, __u._M_device);
    00573     std::swap(_M_owns, __u._M_owns);
    00574       }
    00575
    00576       mutex_type*
    00577       release()
    00578       {
    00579     mutex_type* __ret = _M_device;
    00580     _M_device = 0;
    00581     _M_owns = false;
    00582     return __ret;
    00583       }
    00584
    00585       bool
    00586       owns_lock() const
    00587       { return _M_owns; }
    00588
    00589       /* explicit */ operator bool () const
    00590       { return owns_lock(); }
    00591
    00592       mutex_type*
    00593       mutex() const
    00594       { return _M_device; }
    00595
    00596     private:
    00597       mutex_type*   _M_device;
    00598       bool      _M_owns; // XXX use atomic_bool
    00599     };
    00600
    00601   template<typename _Mutex>
    00602     inline void
    00603     swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y)
    00604     { __x.swap(__y); }
    00605
    00606   template<typename _Mutex>
    00607     inline void
    00608     swap(unique_lock<_Mutex>&& __x, unique_lock<_Mutex>& __y)
    00609     { __x.swap(__y); }
    00610
    00611   template<typename _Mutex>
    00612     inline void
    00613     swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>&& __y)
    00614     { __x.swap(__y); }
    00615
    00616   template<int _Idx>
    00617     struct __unlock_impl
    00618     {
    00619       template<typename... _Lock>
    00620     static void
    00621     __do_unlock(tuple<_Lock&...>& __locks)
    00622     {
    00623       std::get<_Idx>(__locks).unlock();
    00624       __unlock_impl<_Idx - 1>::__do_unlock(__locks);
    00625     }
    00626     };
    00627
    00628   template<>
    00629     struct __unlock_impl<-1>
    00630     {
    00631       template<typename... _Lock>
    00632     static void
    00633     __do_unlock(tuple<_Lock&...>&)
    00634     { }
    00635     };
    00636
    00637   template<int _Idx, bool _Continue = true>
    00638     struct __try_lock_impl
    00639     {
    00640       template<typename... _Lock>
    00641     static int
    00642     __do_try_lock(tuple<_Lock&...>& __locks)
    00643     {
    00644       if(std::get<_Idx>(__locks).try_lock())
    00645         {
    00646           return __try_lock_impl<_Idx + 1,
    00647         _Idx + 2 < sizeof...(_Lock)>::__do_try_lock(__locks);
    00648         }
    00649       else
    00650         {
    00651           __unlock_impl<_Idx>::__do_unlock(__locks);
    00652           return _Idx;
    00653         }
    00654     }
    00655     };
    00656
    00657   template<int _Idx>
    00658     struct __try_lock_impl<_Idx, false>
    00659     {
    00660       template<typename... _Lock>
    00661     static int
    00662     __do_try_lock(tuple<_Lock&...>& __locks)
    00663     {
    00664       if(std::get<_Idx>(__locks).try_lock())
    00665         return -1;
    00666       else
    00667         {
    00668           __unlock_impl<_Idx>::__do_unlock(__locks);
    00669           return _Idx;
    00670         }
    00671     }
    00672     };
    00673
    00674   /** @brief Generic try_lock.
    00675    *  @param __l1 Meets Mutex requirements (try_lock() may throw).
    00676    *  @param __l2 Meets Mutex requirements (try_lock() may throw).
    00677    *  @param __l3 Meets Mutex requirements (try_lock() may throw).
    00678    *  @return Returns -1 if all try_lock() calls return true. Otherwise returns
    00679    *          a 0-based index corresponding to the argument that returned false.
    00680    *  @post Either all arguments are locked, or none will be.
    00681    *
    00682    *  Sequentially calls try_lock() on each argument.
    00683    */
    00684   template<typename _Lock1, typename _Lock2, typename... _Lock3>
    00685     int
    00686     try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3)
    00687     {
    00688       tuple<_Lock1&, _Lock2&, _Lock3&...> __locks(__l1, __l2, __l3...);
    00689       return __try_lock_impl<0>::__do_try_lock(__locks);
    00690     }
    00691
    00692   /// lock
    00693   template<typename _L1, typename _L2, typename ..._L3>
    00694     void
    00695     lock(_L1&, _L2&, _L3&...);
    00696
    00697   /// once_flag
    00698   struct once_flag
    00699   {
    00700   private:
    00701     typedef __gthread_once_t __native_type;
    00702     __native_type  _M_once;
    00703
    00704   public:
    00705     once_flag()
    00706     {
    00707       __native_type __tmp = __GTHREAD_ONCE_INIT;
    00708       _M_once = __tmp;
    00709     }
    00710
    00711     once_flag(const once_flag&) = delete;
    00712     once_flag& operator=(const once_flag&) = delete;
    00713
    00714     template<typename _Callable, typename... _Args>
    00715       friend void
    00716       call_once(once_flag& __once, _Callable __f, _Args&&... __args);
    00717   };
    00718
    00719 #ifdef _GLIBCXX_HAVE_TLS
    00720   extern __thread void* __once_callable;
    00721   extern __thread void (*__once_call)();
    00722
    00723   template<typename _Callable>
    00724     inline void
    00725     __once_call_impl()
    00726     {
    00727       (*(_Callable*)__once_callable)();
    00728     }
    00729 #else
    00730   extern function<void()> __once_functor;
    00731
    00732   extern unique_lock<mutex>&
    00733   __get_once_functor_lock();
    00734 #endif
    00735
    00736   extern "C" void __once_proxy();
    00737
    00738   /// call_once
    00739   template<typename _Callable, typename... _Args>
    00740     void
    00741     call_once(once_flag& __once, _Callable __f, _Args&&... __args)
    00742     {
    00743 #ifdef _GLIBCXX_HAVE_TLS
    00744       auto __bound_functor = bind(__f, __args...);
    00745       __once_callable = &__bound_functor;
    00746       __once_call = &__once_call_impl<decltype(__bound_functor)>;
    00747 #else
    00748       unique_lock<mutex>& __functor_lock = __get_once_functor_lock();
    00749       __functor_lock.lock();
    00750       __once_functor = bind(__f, __args...);
    00751 #endif
    00752
    00753       int __e = __gthread_once(&(__once._M_once), &__once_proxy);
    00754
    00755 #ifndef _GLIBCXX_HAVE_TLS
    00756       if (__functor_lock)
    00757     __functor_lock.unlock();
    00758 #endif
    00759
    00760       if (__e)
    00761     __throw_system_error(__e);
    00762     }
    00763
    00764   // @} group mutexes
    00765 }
    00766
    00767 #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
    00768
    00769 #endif // __GXX_EXPERIMENTAL_CXX0X__
    00770
    00771 #endif // _GLIBCXX_MUTEX