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