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
52namespace 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