libstdc++
mutex
Go to the documentation of this file.
1 // <mutex> -*- C++ -*-
2 
3 // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
4 // Free Software Foundation, Inc.
5 //
6 // This file is part of the GNU ISO C++ Library. This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 3, or (at your option)
10 // any later version.
11 
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 
17 // Under Section 7 of GPL version 3, you are granted additional
18 // permissions described in the GCC Runtime Library Exception, version
19 // 3.1, as published by the Free Software Foundation.
20 
21 // You should have received a copy of the GNU General Public License and
22 // a copy of the GCC Runtime Library Exception along with this program;
23 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 // <http://www.gnu.org/licenses/>.
25 
26 /** @file include/mutex
27  * This is a Standard C++ Library header.
28  */
29 
30 #ifndef _GLIBCXX_MUTEX
31 #define _GLIBCXX_MUTEX 1
32 
33 #pragma GCC system_header
34 
35 #ifndef __GXX_EXPERIMENTAL_CXX0X__
36 # include <bits/c++0x_warning.h>
37 #else
38 
39 #include <tuple>
40 #include <chrono>
41 #include <exception>
42 #include <type_traits>
43 #include <functional>
44 #include <system_error>
45 #include <bits/functexcept.h>
46 #include <bits/gthr.h>
47 #include <bits/move.h> // for std::swap
48 
49 #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
50 
51 namespace std _GLIBCXX_VISIBILITY(default)
52 {
53 _GLIBCXX_BEGIN_NAMESPACE_VERSION
54 
55  /**
56  * @defgroup mutexes Mutexes
57  * @ingroup concurrency
58  *
59  * Classes for mutex support.
60  * @{
61  */
62 
63  /// mutex
64  class mutex
65  {
66  typedef __gthread_mutex_t __native_type;
67  __native_type _M_mutex;
68 
69  public:
70  typedef __native_type* native_handle_type;
71 
72 #ifdef __GTHREAD_MUTEX_INIT
73  constexpr mutex() : _M_mutex(__GTHREAD_MUTEX_INIT) { }
74 #else
75  mutex()
76  {
77  // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
78  __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
79  }
80 
81  ~mutex() { __gthread_mutex_destroy(&_M_mutex); }
82 #endif
83 
84  mutex(const mutex&) = delete;
85  mutex& operator=(const mutex&) = delete;
86 
87  void
88  lock()
89  {
90  int __e = __gthread_mutex_lock(&_M_mutex);
91 
92  // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
93  if (__e)
94  __throw_system_error(__e);
95  }
96 
97  bool
98  try_lock()
99  {
100  // XXX EINVAL, EAGAIN, EBUSY
101  return !__gthread_mutex_trylock(&_M_mutex);
102  }
103 
104  void
105  unlock()
106  {
107  // XXX EINVAL, EAGAIN, EPERM
108  __gthread_mutex_unlock(&_M_mutex);
109  }
110 
111  native_handle_type
112  native_handle()
113  { return &_M_mutex; }
114  };
115 
116 #ifndef __GTHREAD_RECURSIVE_MUTEX_INIT
117  // FIXME: gthreads doesn't define __gthread_recursive_mutex_destroy
118  // so we need to obtain a __gthread_mutex_t to destroy
119  class __destroy_recursive_mutex
120  {
121  template<typename _Mx, typename _Rm>
122  static void
123  _S_destroy_win32(_Mx* __mx, _Rm const* __rmx)
124  {
125  __mx->counter = __rmx->counter;
126  __mx->sema = __rmx->sema;
127  __gthread_mutex_destroy(__mx);
128  }
129 
130  public:
131  // matches a gthr-win32.h recursive mutex
132  template<typename _Rm>
133  static typename enable_if<(bool)sizeof(&_Rm::sema), void>::type
134  _S_destroy(_Rm* __mx)
135  {
136  __gthread_mutex_t __tmp;
137  _S_destroy_win32(&__tmp, __mx);
138  }
139 
140  // matches a recursive mutex with a member 'actual'
141  template<typename _Rm>
142  static typename enable_if<(bool)sizeof(&_Rm::actual), void>::type
143  _S_destroy(_Rm* __mx)
144  { __gthread_mutex_destroy(&__mx->actual); }
145 
146  // matches when there's only one mutex type
147  template<typename _Rm>
148  static
149  typename enable_if<is_same<_Rm, __gthread_mutex_t>::value, void>::type
150  _S_destroy(_Rm* __mx)
151  { __gthread_mutex_destroy(__mx); }
152  };
153 #endif
154 
155  /// recursive_mutex
157  {
158  typedef __gthread_recursive_mutex_t __native_type;
159  __native_type _M_mutex;
160 
161  public:
162  typedef __native_type* native_handle_type;
163 
164 #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT
165  recursive_mutex() : _M_mutex(__GTHREAD_RECURSIVE_MUTEX_INIT) { }
166 #else
168  {
169  // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
170  __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
171  }
172 
173  ~recursive_mutex()
174  { __destroy_recursive_mutex::_S_destroy(&_M_mutex); }
175 #endif
176 
177  recursive_mutex(const recursive_mutex&) = delete;
178  recursive_mutex& operator=(const recursive_mutex&) = delete;
179 
180  void
181  lock()
182  {
183  int __e = __gthread_recursive_mutex_lock(&_M_mutex);
184 
185  // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
186  if (__e)
187  __throw_system_error(__e);
188  }
189 
190  bool
191  try_lock()
192  {
193  // XXX EINVAL, EAGAIN, EBUSY
194  return !__gthread_recursive_mutex_trylock(&_M_mutex);
195  }
196 
197  void
198  unlock()
199  {
200  // XXX EINVAL, EAGAIN, EBUSY
201  __gthread_recursive_mutex_unlock(&_M_mutex);
202  }
203 
204  native_handle_type
205  native_handle()
206  { return &_M_mutex; }
207  };
208 
209  /// timed_mutex
211  {
212  typedef __gthread_mutex_t __native_type;
213 
214 #ifdef _GLIBCXX_USE_CLOCK_MONOTONIC
216 #else
218 #endif
219 
220  __native_type _M_mutex;
221 
222  public:
223  typedef __native_type* native_handle_type;
224 
225 #ifdef __GTHREAD_MUTEX_INIT
226  timed_mutex() : _M_mutex(__GTHREAD_MUTEX_INIT) { }
227 #else
228  timed_mutex()
229  {
230  __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
231  }
232 
233  ~timed_mutex() { __gthread_mutex_destroy(&_M_mutex); }
234 #endif
235 
236  timed_mutex(const timed_mutex&) = delete;
237  timed_mutex& operator=(const timed_mutex&) = delete;
238 
239  void
240  lock()
241  {
242  int __e = __gthread_mutex_lock(&_M_mutex);
243 
244  // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
245  if (__e)
246  __throw_system_error(__e);
247  }
248 
249  bool
250  try_lock()
251  {
252  // XXX EINVAL, EAGAIN, EBUSY
253  return !__gthread_mutex_trylock(&_M_mutex);
254  }
255 
256  template <class _Rep, class _Period>
257  bool
258  try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
259  { return __try_lock_for_impl(__rtime); }
260 
261  template <class _Clock, class _Duration>
262  bool
263  try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
264  {
267 
268  chrono::nanoseconds __ns =
270 
271  __gthread_time_t __ts = {
272  static_cast<std::time_t>(__s.time_since_epoch().count()),
273  static_cast<long>(__ns.count())
274  };
275 
276  return !__gthread_mutex_timedlock(&_M_mutex, &__ts);
277  }
278 
279  void
280  unlock()
281  {
282  // XXX EINVAL, EAGAIN, EBUSY
283  __gthread_mutex_unlock(&_M_mutex);
284  }
285 
286  native_handle_type
287  native_handle()
288  { return &_M_mutex; }
289 
290  private:
291  template<typename _Rep, typename _Period>
292  typename enable_if<
293  ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
294  __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
295  {
296  __clock_t::time_point __atime = __clock_t::now()
298 
299  return try_lock_until(__atime);
300  }
301 
302  template <typename _Rep, typename _Period>
303  typename enable_if<
304  !ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
305  __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
306  {
307  __clock_t::time_point __atime = __clock_t::now()
309 
310  return try_lock_until(__atime);
311  }
312  };
313 
314  /// recursive_timed_mutex
316  {
317  typedef __gthread_recursive_mutex_t __native_type;
318 
319 #ifdef _GLIBCXX_USE_CLOCK_MONOTONIC
321 #else
323 #endif
324 
325  __native_type _M_mutex;
326 
327  public:
328  typedef __native_type* native_handle_type;
329 
330 #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT
331  recursive_timed_mutex() : _M_mutex(__GTHREAD_RECURSIVE_MUTEX_INIT) { }
332 #else
334  {
335  // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
336  __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
337  }
338 
340  { __destroy_recursive_mutex::_S_destroy(&_M_mutex); }
341 #endif
342 
344  recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
345 
346  void
347  lock()
348  {
349  int __e = __gthread_recursive_mutex_lock(&_M_mutex);
350 
351  // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
352  if (__e)
353  __throw_system_error(__e);
354  }
355 
356  bool
357  try_lock()
358  {
359  // XXX EINVAL, EAGAIN, EBUSY
360  return !__gthread_recursive_mutex_trylock(&_M_mutex);
361  }
362 
363  template <class _Rep, class _Period>
364  bool
365  try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
366  { return __try_lock_for_impl(__rtime); }
367 
368  template <class _Clock, class _Duration>
369  bool
370  try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
371  {
374 
375  chrono::nanoseconds __ns =
377 
378  __gthread_time_t __ts = {
379  static_cast<std::time_t>(__s.time_since_epoch().count()),
380  static_cast<long>(__ns.count())
381  };
382 
383  return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts);
384  }
385 
386  void
387  unlock()
388  {
389  // XXX EINVAL, EAGAIN, EBUSY
390  __gthread_recursive_mutex_unlock(&_M_mutex);
391  }
392 
393  native_handle_type
394  native_handle()
395  { return &_M_mutex; }
396 
397  private:
398  template<typename _Rep, typename _Period>
399  typename enable_if<
400  ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
401  __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
402  {
403  __clock_t::time_point __atime = __clock_t::now()
405 
406  return try_lock_until(__atime);
407  }
408 
409  template <typename _Rep, typename _Period>
410  typename enable_if<
411  !ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
412  __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
413  {
414  __clock_t::time_point __atime = __clock_t::now()
416 
417  return try_lock_until(__atime);
418  }
419  };
420 
421  /// Do not acquire ownership of the mutex.
422  struct defer_lock_t { };
423 
424  /// Try to acquire ownership of the mutex without blocking.
425  struct try_to_lock_t { };
426 
427  /// Assume the calling thread has already obtained mutex ownership
428  /// and manage it.
429  struct adopt_lock_t { };
430 
431  constexpr defer_lock_t defer_lock { };
432  constexpr try_to_lock_t try_to_lock { };
433  constexpr adopt_lock_t adopt_lock { };
434 
435  /// @brief Scoped lock idiom.
436  // Acquire the mutex here with a constructor call, then release with
437  // the destructor call in accordance with RAII style.
438  template<typename _Mutex>
440  {
441  public:
442  typedef _Mutex mutex_type;
443 
444  explicit lock_guard(mutex_type& __m) : _M_device(__m)
445  { _M_device.lock(); }
446 
447  lock_guard(mutex_type& __m, adopt_lock_t) : _M_device(__m)
448  { } // calling thread owns mutex
449 
450  ~lock_guard()
451  { _M_device.unlock(); }
452 
453  lock_guard(const lock_guard&) = delete;
454  lock_guard& operator=(const lock_guard&) = delete;
455 
456  private:
457  mutex_type& _M_device;
458  };
459 
460  /// unique_lock
461  template<typename _Mutex>
463  {
464  public:
465  typedef _Mutex mutex_type;
466 
467  unique_lock()
468  : _M_device(0), _M_owns(false)
469  { }
470 
471  explicit unique_lock(mutex_type& __m)
472  : _M_device(&__m), _M_owns(false)
473  {
474  lock();
475  _M_owns = true;
476  }
477 
478  unique_lock(mutex_type& __m, defer_lock_t)
479  : _M_device(&__m), _M_owns(false)
480  { }
481 
482  unique_lock(mutex_type& __m, try_to_lock_t)
483  : _M_device(&__m), _M_owns(_M_device->try_lock())
484  { }
485 
486  unique_lock(mutex_type& __m, adopt_lock_t)
487  : _M_device(&__m), _M_owns(true)
488  {
489  // XXX calling thread owns mutex
490  }
491 
492  template<typename _Clock, typename _Duration>
493  unique_lock(mutex_type& __m,
495  : _M_device(&__m), _M_owns(_M_device->try_lock_until(__atime))
496  { }
497 
498  template<typename _Rep, typename _Period>
499  unique_lock(mutex_type& __m,
500  const chrono::duration<_Rep, _Period>& __rtime)
501  : _M_device(&__m), _M_owns(_M_device->try_lock_for(__rtime))
502  { }
503 
504  ~unique_lock()
505  {
506  if (_M_owns)
507  unlock();
508  }
509 
510  unique_lock(const unique_lock&) = delete;
511  unique_lock& operator=(const unique_lock&) = delete;
512 
513  unique_lock(unique_lock&& __u)
514  : _M_device(__u._M_device), _M_owns(__u._M_owns)
515  {
516  __u._M_device = 0;
517  __u._M_owns = false;
518  }
519 
520  unique_lock& operator=(unique_lock&& __u)
521  {
522  if(_M_owns)
523  unlock();
524 
525  unique_lock(std::move(__u)).swap(*this);
526 
527  __u._M_device = 0;
528  __u._M_owns = false;
529 
530  return *this;
531  }
532 
533  void
534  lock()
535  {
536  if (!_M_device)
537  __throw_system_error(int(errc::operation_not_permitted));
538  else if (_M_owns)
539  __throw_system_error(int(errc::resource_deadlock_would_occur));
540  else
541  {
542  _M_device->lock();
543  _M_owns = true;
544  }
545  }
546 
547  bool
548  try_lock()
549  {
550  if (!_M_device)
551  __throw_system_error(int(errc::operation_not_permitted));
552  else if (_M_owns)
553  __throw_system_error(int(errc::resource_deadlock_would_occur));
554  else
555  {
556  _M_owns = _M_device->try_lock();
557  return _M_owns;
558  }
559  }
560 
561  template<typename _Clock, typename _Duration>
562  bool
563  try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
564  {
565  if (!_M_device)
566  __throw_system_error(int(errc::operation_not_permitted));
567  else if (_M_owns)
568  __throw_system_error(int(errc::resource_deadlock_would_occur));
569  else
570  {
571  _M_owns = _M_device->try_lock_until(__atime);
572  return _M_owns;
573  }
574  }
575 
576  template<typename _Rep, typename _Period>
577  bool
578  try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
579  {
580  if (!_M_device)
581  __throw_system_error(int(errc::operation_not_permitted));
582  else if (_M_owns)
583  __throw_system_error(int(errc::resource_deadlock_would_occur));
584  else
585  {
586  _M_owns = _M_device->try_lock_for(__rtime);
587  return _M_owns;
588  }
589  }
590 
591  void
592  unlock()
593  {
594  if (!_M_owns)
595  __throw_system_error(int(errc::operation_not_permitted));
596  else if (_M_device)
597  {
598  _M_device->unlock();
599  _M_owns = false;
600  }
601  }
602 
603  void
604  swap(unique_lock& __u)
605  {
606  std::swap(_M_device, __u._M_device);
607  std::swap(_M_owns, __u._M_owns);
608  }
609 
610  mutex_type*
611  release()
612  {
613  mutex_type* __ret = _M_device;
614  _M_device = 0;
615  _M_owns = false;
616  return __ret;
617  }
618 
619  bool
620  owns_lock() const
621  { return _M_owns; }
622 
623  explicit operator bool() const
624  { return owns_lock(); }
625 
626  mutex_type*
627  mutex() const
628  { return _M_device; }
629 
630  private:
631  mutex_type* _M_device;
632  bool _M_owns; // XXX use atomic_bool
633  };
634 
635  template<typename _Mutex>
636  inline void
638  { __x.swap(__y); }
639 
640  template<int _Idx>
641  struct __unlock_impl
642  {
643  template<typename... _Lock>
644  static void
645  __do_unlock(tuple<_Lock&...>& __locks)
646  {
647  std::get<_Idx>(__locks).unlock();
648  __unlock_impl<_Idx - 1>::__do_unlock(__locks);
649  }
650  };
651 
652  template<>
653  struct __unlock_impl<-1>
654  {
655  template<typename... _Lock>
656  static void
657  __do_unlock(tuple<_Lock&...>&)
658  { }
659  };
660 
661  template<typename _Lock>
662  unique_lock<_Lock>
663  __try_to_lock(_Lock& __l)
664  { return unique_lock<_Lock>(__l, try_to_lock); }
665 
666  template<int _Idx, bool _Continue = true>
667  struct __try_lock_impl
668  {
669  template<typename... _Lock>
670  static void
671  __do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
672  {
673  __idx = _Idx;
674  auto __lock = __try_to_lock(std::get<_Idx>(__locks));
675  if (__lock.owns_lock())
676  {
677  __try_lock_impl<_Idx + 1, _Idx + 2 < sizeof...(_Lock)>::
678  __do_try_lock(__locks, __idx);
679  if (__idx == -1)
680  __lock.release();
681  }
682  }
683  };
684 
685  template<int _Idx>
686  struct __try_lock_impl<_Idx, false>
687  {
688  template<typename... _Lock>
689  static void
690  __do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
691  {
692  __idx = _Idx;
693  auto __lock = __try_to_lock(std::get<_Idx>(__locks));
694  if (__lock.owns_lock())
695  {
696  __idx = -1;
697  __lock.release();
698  }
699  }
700  };
701 
702  /** @brief Generic try_lock.
703  * @param __l1 Meets Mutex requirements (try_lock() may throw).
704  * @param __l2 Meets Mutex requirements (try_lock() may throw).
705  * @param __l3 Meets Mutex requirements (try_lock() may throw).
706  * @return Returns -1 if all try_lock() calls return true. Otherwise returns
707  * a 0-based index corresponding to the argument that returned false.
708  * @post Either all arguments are locked, or none will be.
709  *
710  * Sequentially calls try_lock() on each argument.
711  */
712  template<typename _Lock1, typename _Lock2, typename... _Lock3>
713  int
714  try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3)
715  {
716  int __idx;
717  auto __locks = std::tie(__l1, __l2, __l3...);
718  __try
719  { __try_lock_impl<0>::__do_try_lock(__locks, __idx); }
720  __catch(...)
721  { }
722  return __idx;
723  }
724 
725  /** @brief Generic lock.
726  * @param __l1 Meets Mutex requirements (try_lock() may throw).
727  * @param __l2 Meets Mutex requirements (try_lock() may throw).
728  * @param __l3 Meets Mutex requirements (try_lock() may throw).
729  * @throw An exception thrown by an argument's lock() or try_lock() member.
730  * @post All arguments are locked.
731  *
732  * All arguments are locked via a sequence of calls to lock(), try_lock()
733  * and unlock(). If the call exits via an exception any locks that were
734  * obtained will be released.
735  */
736  template<typename _L1, typename _L2, typename ..._L3>
737  void
738  lock(_L1& __l1, _L2& __l2, _L3&... __l3)
739  {
740  while (true)
741  {
742  unique_lock<_L1> __first(__l1);
743  int __idx;
744  auto __locks = std::tie(__l2, __l3...);
745  __try_lock_impl<0, sizeof...(_L3)>::__do_try_lock(__locks, __idx);
746  if (__idx == -1)
747  {
748  __first.release();
749  return;
750  }
751  }
752  }
753 
754  /// once_flag
755  struct once_flag
756  {
757  private:
758  typedef __gthread_once_t __native_type;
759  __native_type _M_once;
760 
761  public:
762  constexpr once_flag() : _M_once(__GTHREAD_ONCE_INIT) { }
763 
764  once_flag(const once_flag&) = delete;
765  once_flag& operator=(const once_flag&) = delete;
766 
767  template<typename _Callable, typename... _Args>
768  friend void
769  call_once(once_flag& __once, _Callable&& __f, _Args&&... __args);
770  };
771 
772 #ifdef _GLIBCXX_HAVE_TLS
773  extern __thread void* __once_callable;
774  extern __thread void (*__once_call)();
775 
776  template<typename _Callable>
777  inline void
778  __once_call_impl()
779  {
780  (*(_Callable*)__once_callable)();
781  }
782 #else
783  extern function<void()> __once_functor;
784 
785  extern void
786  __set_once_functor_lock_ptr(unique_lock<mutex>*);
787 
788  extern mutex&
789  __get_once_mutex();
790 #endif
791 
792  extern "C" void __once_proxy();
793 
794  /// call_once
795  template<typename _Callable, typename... _Args>
796  void
797  call_once(once_flag& __once, _Callable&& __f, _Args&&... __args)
798  {
799 #ifdef _GLIBCXX_HAVE_TLS
800  auto __bound_functor = std::bind<void>(std::forward<_Callable>(__f),
801  std::forward<_Args>(__args)...);
802  __once_callable = &__bound_functor;
803  __once_call = &__once_call_impl<decltype(__bound_functor)>;
804 #else
805  unique_lock<mutex> __functor_lock(__get_once_mutex());
806  __once_functor = std::bind<void>(std::forward<_Callable>(__f),
807  std::forward<_Args>(__args)...);
808  __set_once_functor_lock_ptr(&__functor_lock);
809 #endif
810 
811  int __e = __gthread_once(&(__once._M_once), &__once_proxy);
812 
813 #ifndef _GLIBCXX_HAVE_TLS
814  if (__functor_lock)
815  __set_once_functor_lock_ptr(0);
816 #endif
817 
818  if (__e)
819  __throw_system_error(__e);
820  }
821 
822  // @} group mutexes
823 _GLIBCXX_END_NAMESPACE_VERSION
824 } // namespace
825 
826 #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
827 
828 #endif // __GXX_EXPERIMENTAL_CXX0X__
829 
830 #endif // _GLIBCXX_MUTEX