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