libstdc++
mutex
Go to the documentation of this file.
1 // <mutex> -*- C++ -*-
2 
3 // Copyright (C) 2003-2016 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/std_mutex.h>
45 #if ! _GTHREAD_USE_MUTEX_TIMEDLOCK
46 # include <condition_variable>
47 # include <thread>
48 #endif
49 
50 #ifdef _GLIBCXX_USE_C99_STDINT_TR1
51 
52 namespace std _GLIBCXX_VISIBILITY(default)
53 {
54 _GLIBCXX_BEGIN_NAMESPACE_VERSION
55 
56  /**
57  * @ingroup mutexes
58  * @{
59  */
60 
61 #ifdef _GLIBCXX_HAS_GTHREADS
62 
63  // Common base class for std::recursive_mutex and std::recursive_timed_mutex
64  class __recursive_mutex_base
65  {
66  protected:
67  typedef __gthread_recursive_mutex_t __native_type;
68 
69  __recursive_mutex_base(const __recursive_mutex_base&) = delete;
70  __recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete;
71 
72 #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT
73  __native_type _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT;
74 
75  __recursive_mutex_base() = default;
76 #else
77  __native_type _M_mutex;
78 
79  __recursive_mutex_base()
80  {
81  // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
82  __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
83  }
84 
85  ~__recursive_mutex_base()
86  { __gthread_recursive_mutex_destroy(&_M_mutex); }
87 #endif
88  };
89 
90  /// The standard recursive mutex type.
91  class recursive_mutex : private __recursive_mutex_base
92  {
93  public:
94  typedef __native_type* native_handle_type;
95 
96  recursive_mutex() = default;
97  ~recursive_mutex() = default;
98 
99  recursive_mutex(const recursive_mutex&) = delete;
100  recursive_mutex& operator=(const recursive_mutex&) = delete;
101 
102  void
103  lock()
104  {
105  int __e = __gthread_recursive_mutex_lock(&_M_mutex);
106 
107  // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
108  if (__e)
109  __throw_system_error(__e);
110  }
111 
112  bool
113  try_lock() noexcept
114  {
115  // XXX EINVAL, EAGAIN, EBUSY
116  return !__gthread_recursive_mutex_trylock(&_M_mutex);
117  }
118 
119  void
120  unlock()
121  {
122  // XXX EINVAL, EAGAIN, EBUSY
123  __gthread_recursive_mutex_unlock(&_M_mutex);
124  }
125 
126  native_handle_type
127  native_handle()
128  { return &_M_mutex; }
129  };
130 
131 #if _GTHREAD_USE_MUTEX_TIMEDLOCK
132  template<typename _Derived>
133  class __timed_mutex_impl
134  {
135  protected:
136  typedef chrono::high_resolution_clock __clock_t;
137 
138  template<typename _Rep, typename _Period>
139  bool
140  _M_try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
141  {
142  using chrono::steady_clock;
143  auto __rt = chrono::duration_cast<steady_clock::duration>(__rtime);
144  if (ratio_greater<steady_clock::period, _Period>())
145  ++__rt;
146  return _M_try_lock_until(steady_clock::now() + __rt);
147  }
148 
149  template<typename _Duration>
150  bool
151  _M_try_lock_until(const chrono::time_point<__clock_t,
152  _Duration>& __atime)
153  {
154  auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
155  auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
156 
157  __gthread_time_t __ts = {
158  static_cast<std::time_t>(__s.time_since_epoch().count()),
159  static_cast<long>(__ns.count())
160  };
161 
162  return static_cast<_Derived*>(this)->_M_timedlock(__ts);
163  }
164 
165  template<typename _Clock, typename _Duration>
166  bool
167  _M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
168  {
169  auto __rtime = __atime - _Clock::now();
170  return _M_try_lock_until(__clock_t::now() + __rtime);
171  }
172  };
173 
174  /// The standard timed mutex type.
175  class timed_mutex
176  : private __mutex_base, public __timed_mutex_impl<timed_mutex>
177  {
178  public:
179  typedef __native_type* native_handle_type;
180 
181  timed_mutex() = default;
182  ~timed_mutex() = default;
183 
184  timed_mutex(const timed_mutex&) = delete;
185  timed_mutex& operator=(const timed_mutex&) = delete;
186 
187  void
188  lock()
189  {
190  int __e = __gthread_mutex_lock(&_M_mutex);
191 
192  // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
193  if (__e)
194  __throw_system_error(__e);
195  }
196 
197  bool
198  try_lock() noexcept
199  {
200  // XXX EINVAL, EAGAIN, EBUSY
201  return !__gthread_mutex_trylock(&_M_mutex);
202  }
203 
204  template <class _Rep, class _Period>
205  bool
206  try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
207  { return _M_try_lock_for(__rtime); }
208 
209  template <class _Clock, class _Duration>
210  bool
211  try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
212  { return _M_try_lock_until(__atime); }
213 
214  void
215  unlock()
216  {
217  // XXX EINVAL, EAGAIN, EBUSY
218  __gthread_mutex_unlock(&_M_mutex);
219  }
220 
221  native_handle_type
222  native_handle()
223  { return &_M_mutex; }
224 
225  private:
226  friend class __timed_mutex_impl<timed_mutex>;
227 
228  bool
229  _M_timedlock(const __gthread_time_t& __ts)
230  { return !__gthread_mutex_timedlock(&_M_mutex, &__ts); }
231  };
232 
233  /// recursive_timed_mutex
234  class recursive_timed_mutex
235  : private __recursive_mutex_base,
236  public __timed_mutex_impl<recursive_timed_mutex>
237  {
238  public:
239  typedef __native_type* native_handle_type;
240 
241  recursive_timed_mutex() = default;
242  ~recursive_timed_mutex() = default;
243 
244  recursive_timed_mutex(const recursive_timed_mutex&) = delete;
245  recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
246 
247  void
248  lock()
249  {
250  int __e = __gthread_recursive_mutex_lock(&_M_mutex);
251 
252  // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
253  if (__e)
254  __throw_system_error(__e);
255  }
256 
257  bool
258  try_lock() noexcept
259  {
260  // XXX EINVAL, EAGAIN, EBUSY
261  return !__gthread_recursive_mutex_trylock(&_M_mutex);
262  }
263 
264  template <class _Rep, class _Period>
265  bool
266  try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
267  { return _M_try_lock_for(__rtime); }
268 
269  template <class _Clock, class _Duration>
270  bool
271  try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
272  { return _M_try_lock_until(__atime); }
273 
274  void
275  unlock()
276  {
277  // XXX EINVAL, EAGAIN, EBUSY
278  __gthread_recursive_mutex_unlock(&_M_mutex);
279  }
280 
281  native_handle_type
282  native_handle()
283  { return &_M_mutex; }
284 
285  private:
286  friend class __timed_mutex_impl<recursive_timed_mutex>;
287 
288  bool
289  _M_timedlock(const __gthread_time_t& __ts)
290  { return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts); }
291  };
292 
293 #else // !_GTHREAD_USE_MUTEX_TIMEDLOCK
294 
295  /// timed_mutex
296  class timed_mutex
297  {
298  mutex _M_mut;
299  condition_variable _M_cv;
300  bool _M_locked = false;
301 
302  public:
303 
304  timed_mutex() = default;
305  ~timed_mutex() { __glibcxx_assert( !_M_locked ); }
306 
307  timed_mutex(const timed_mutex&) = delete;
308  timed_mutex& operator=(const timed_mutex&) = delete;
309 
310  void
311  lock()
312  {
313  unique_lock<mutex> __lk(_M_mut);
314  _M_cv.wait(__lk, [&]{ return !_M_locked; });
315  _M_locked = true;
316  }
317 
318  bool
319  try_lock()
320  {
321  lock_guard<mutex> __lk(_M_mut);
322  if (_M_locked)
323  return false;
324  _M_locked = true;
325  return true;
326  }
327 
328  template<typename _Rep, typename _Period>
329  bool
330  try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
331  {
332  unique_lock<mutex> __lk(_M_mut);
333  if (!_M_cv.wait_for(__lk, __rtime, [&]{ return !_M_locked; }))
334  return false;
335  _M_locked = true;
336  return true;
337  }
338 
339  template<typename _Clock, typename _Duration>
340  bool
341  try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
342  {
343  unique_lock<mutex> __lk(_M_mut);
344  if (!_M_cv.wait_until(__lk, __atime, [&]{ return !_M_locked; }))
345  return false;
346  _M_locked = true;
347  return true;
348  }
349 
350  void
351  unlock()
352  {
353  lock_guard<mutex> __lk(_M_mut);
354  __glibcxx_assert( _M_locked );
355  _M_locked = false;
356  _M_cv.notify_one();
357  }
358  };
359 
360  /// recursive_timed_mutex
361  class recursive_timed_mutex
362  {
363  mutex _M_mut;
364  condition_variable _M_cv;
365  thread::id _M_owner;
366  unsigned _M_count = 0;
367 
368  // Predicate type that tests whether the current thread can lock a mutex.
369  struct _Can_lock
370  {
371  // Returns true if the mutex is unlocked or is locked by _M_caller.
372  bool
373  operator()() const noexcept
374  { return _M_mx->_M_count == 0 || _M_mx->_M_owner == _M_caller; }
375 
376  const recursive_timed_mutex* _M_mx;
377  thread::id _M_caller;
378  };
379 
380  public:
381 
382  recursive_timed_mutex() = default;
383  ~recursive_timed_mutex() { __glibcxx_assert( _M_count == 0 ); }
384 
385  recursive_timed_mutex(const recursive_timed_mutex&) = delete;
386  recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
387 
388  void
389  lock()
390  {
391  auto __id = this_thread::get_id();
392  _Can_lock __can_lock{this, __id};
393  unique_lock<mutex> __lk(_M_mut);
394  _M_cv.wait(__lk, __can_lock);
395  if (_M_count == -1u)
396  __throw_system_error(EAGAIN); // [thread.timedmutex.recursive]/3
397  _M_owner = __id;
398  ++_M_count;
399  }
400 
401  bool
402  try_lock()
403  {
404  auto __id = this_thread::get_id();
405  _Can_lock __can_lock{this, __id};
406  lock_guard<mutex> __lk(_M_mut);
407  if (!__can_lock())
408  return false;
409  if (_M_count == -1u)
410  return false;
411  _M_owner = __id;
412  ++_M_count;
413  return true;
414  }
415 
416  template<typename _Rep, typename _Period>
417  bool
418  try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
419  {
420  auto __id = this_thread::get_id();
421  _Can_lock __can_lock{this, __id};
422  unique_lock<mutex> __lk(_M_mut);
423  if (!_M_cv.wait_for(__lk, __rtime, __can_lock))
424  return false;
425  if (_M_count == -1u)
426  return false;
427  _M_owner = __id;
428  ++_M_count;
429  return true;
430  }
431 
432  template<typename _Clock, typename _Duration>
433  bool
434  try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
435  {
436  auto __id = this_thread::get_id();
437  _Can_lock __can_lock{this, __id};
438  unique_lock<mutex> __lk(_M_mut);
439  if (!_M_cv.wait_until(__lk, __atime, __can_lock))
440  return false;
441  if (_M_count == -1u)
442  return false;
443  _M_owner = __id;
444  ++_M_count;
445  return true;
446  }
447 
448  void
449  unlock()
450  {
451  lock_guard<mutex> __lk(_M_mut);
452  __glibcxx_assert( _M_owner == this_thread::get_id() );
453  __glibcxx_assert( _M_count > 0 );
454  if (--_M_count == 0)
455  {
456  _M_owner = {};
457  _M_cv.notify_one();
458  }
459  }
460  };
461 
462 #endif
463 #endif // _GLIBCXX_HAS_GTHREADS
464 
465  template<typename _Lock>
466  inline unique_lock<_Lock>
467  __try_to_lock(_Lock& __l)
468  { return unique_lock<_Lock>{__l, try_to_lock}; }
469 
470  template<int _Idx, bool _Continue = true>
471  struct __try_lock_impl
472  {
473  template<typename... _Lock>
474  static void
475  __do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
476  {
477  __idx = _Idx;
478  auto __lock = std::__try_to_lock(std::get<_Idx>(__locks));
479  if (__lock.owns_lock())
480  {
481  constexpr bool __cont = _Idx + 2 < sizeof...(_Lock);
482  using __try_locker = __try_lock_impl<_Idx + 1, __cont>;
483  __try_locker::__do_try_lock(__locks, __idx);
484  if (__idx == -1)
485  __lock.release();
486  }
487  }
488  };
489 
490  template<int _Idx>
491  struct __try_lock_impl<_Idx, false>
492  {
493  template<typename... _Lock>
494  static void
495  __do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
496  {
497  __idx = _Idx;
498  auto __lock = std::__try_to_lock(std::get<_Idx>(__locks));
499  if (__lock.owns_lock())
500  {
501  __idx = -1;
502  __lock.release();
503  }
504  }
505  };
506 
507  /** @brief Generic try_lock.
508  * @param __l1 Meets Mutex requirements (try_lock() may throw).
509  * @param __l2 Meets Mutex requirements (try_lock() may throw).
510  * @param __l3 Meets Mutex requirements (try_lock() may throw).
511  * @return Returns -1 if all try_lock() calls return true. Otherwise returns
512  * a 0-based index corresponding to the argument that returned false.
513  * @post Either all arguments are locked, or none will be.
514  *
515  * Sequentially calls try_lock() on each argument.
516  */
517  template<typename _Lock1, typename _Lock2, typename... _Lock3>
518  int
519  try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3)
520  {
521  int __idx;
522  auto __locks = std::tie(__l1, __l2, __l3...);
523  __try_lock_impl<0>::__do_try_lock(__locks, __idx);
524  return __idx;
525  }
526 
527  /** @brief Generic lock.
528  * @param __l1 Meets Mutex requirements (try_lock() may throw).
529  * @param __l2 Meets Mutex requirements (try_lock() may throw).
530  * @param __l3 Meets Mutex requirements (try_lock() may throw).
531  * @throw An exception thrown by an argument's lock() or try_lock() member.
532  * @post All arguments are locked.
533  *
534  * All arguments are locked via a sequence of calls to lock(), try_lock()
535  * and unlock(). If the call exits via an exception any locks that were
536  * obtained will be released.
537  */
538  template<typename _L1, typename _L2, typename... _L3>
539  void
540  lock(_L1& __l1, _L2& __l2, _L3&... __l3)
541  {
542  while (true)
543  {
544  using __try_locker = __try_lock_impl<0, sizeof...(_L3) != 0>;
545  unique_lock<_L1> __first(__l1);
546  int __idx;
547  auto __locks = std::tie(__l2, __l3...);
548  __try_locker::__do_try_lock(__locks, __idx);
549  if (__idx == -1)
550  {
551  __first.release();
552  return;
553  }
554  }
555  }
556 
557 #ifdef _GLIBCXX_HAS_GTHREADS
558  /// once_flag
559  struct once_flag
560  {
561  private:
562  typedef __gthread_once_t __native_type;
563  __native_type _M_once = __GTHREAD_ONCE_INIT;
564 
565  public:
566  /// Constructor
567  constexpr once_flag() noexcept = default;
568 
569  /// Deleted copy constructor
570  once_flag(const once_flag&) = delete;
571  /// Deleted assignment operator
572  once_flag& operator=(const once_flag&) = delete;
573 
574  template<typename _Callable, typename... _Args>
575  friend void
576  call_once(once_flag& __once, _Callable&& __f, _Args&&... __args);
577  };
578 
579 #ifdef _GLIBCXX_HAVE_TLS
580  extern __thread void* __once_callable;
581  extern __thread void (*__once_call)();
582 #else
583  extern function<void()> __once_functor;
584 
585  extern void
586  __set_once_functor_lock_ptr(unique_lock<mutex>*);
587 
588  extern mutex&
589  __get_once_mutex();
590 #endif
591 
592  extern "C" void __once_proxy(void);
593 
594  /// call_once
595  template<typename _Callable, typename... _Args>
596  void
597  call_once(once_flag& __once, _Callable&& __f, _Args&&... __args)
598  {
599  // _GLIBCXX_RESOLVE_LIB_DEFECTS
600  // 2442. call_once() shouldn't DECAY_COPY()
601  auto __callable = [&] {
602  std::__invoke(std::forward<_Callable>(__f),
603  std::forward<_Args>(__args)...);
604  };
605 #ifdef _GLIBCXX_HAVE_TLS
606  __once_callable = std::__addressof(__callable);
607  __once_call = []{ (*(decltype(__callable)*)__once_callable)(); };
608 #else
609  unique_lock<mutex> __functor_lock(__get_once_mutex());
610  __once_functor = __callable;
611  __set_once_functor_lock_ptr(&__functor_lock);
612 #endif
613 
614  int __e = __gthread_once(&__once._M_once, &__once_proxy);
615 
616 #ifndef _GLIBCXX_HAVE_TLS
617  if (__functor_lock)
618  __set_once_functor_lock_ptr(0);
619 #endif
620 
621  if (__e)
622  __throw_system_error(__e);
623  }
624 #endif // _GLIBCXX_HAS_GTHREADS
625 
626  // @} group mutexes
627 _GLIBCXX_END_NAMESPACE_VERSION
628 } // namespace
629 #endif // _GLIBCXX_USE_C99_STDINT_TR1
630 
631 #endif // C++11
632 
633 #endif // _GLIBCXX_MUTEX