|
libstdc++
|
00001 // <mutex> -*- C++ -*- 00002 00003 // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013 00004 // Free Software Foundation, Inc. 00005 // 00006 // This file is part of the GNU ISO C++ Library. This library is free 00007 // software; you can redistribute it and/or modify it under the 00008 // terms of the GNU General Public License as published by the 00009 // Free Software Foundation; either version 3, or (at your option) 00010 // any later version. 00011 00012 // This library is distributed in the hope that it will be useful, 00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 // GNU General Public License for more details. 00016 00017 // Under Section 7 of GPL version 3, you are granted additional 00018 // permissions described in the GCC Runtime Library Exception, version 00019 // 3.1, as published by the Free Software Foundation. 00020 00021 // You should have received a copy of the GNU General Public License and 00022 // a copy of the GCC Runtime Library Exception along with this program; 00023 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 00024 // <http://www.gnu.org/licenses/>. 00025 00026 /** @file include/mutex 00027 * This is a Standard C++ Library header. 00028 */ 00029 00030 #ifndef _GLIBCXX_MUTEX 00031 #define _GLIBCXX_MUTEX 1 00032 00033 #pragma GCC system_header 00034 00035 #ifndef __GXX_EXPERIMENTAL_CXX0X__ 00036 # include <bits/c++0x_warning.h> 00037 #else 00038 00039 #include <tuple> 00040 #include <chrono> 00041 #include <exception> 00042 #include <type_traits> 00043 #include <functional> 00044 #include <system_error> 00045 #include <bits/functexcept.h> 00046 #include <bits/gthr.h> 00047 #include <bits/move.h> // for std::swap 00048 00049 #ifdef _GLIBCXX_USE_C99_STDINT_TR1 00050 00051 namespace std _GLIBCXX_VISIBILITY(default) 00052 { 00053 _GLIBCXX_BEGIN_NAMESPACE_VERSION 00054 00055 #ifdef _GLIBCXX_HAS_GTHREADS 00056 // Common base class for std::mutex and std::timed_mutex 00057 class __mutex_base 00058 { 00059 protected: 00060 typedef __gthread_mutex_t __native_type; 00061 00062 #ifdef __GTHREAD_MUTEX_INIT 00063 __native_type _M_mutex = __GTHREAD_MUTEX_INIT; 00064 00065 constexpr __mutex_base() noexcept = default; 00066 #else 00067 __native_type _M_mutex; 00068 00069 __mutex_base() noexcept 00070 { 00071 // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may) 00072 __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); 00073 } 00074 00075 ~__mutex_base() noexcept { __gthread_mutex_destroy(&_M_mutex); } 00076 #endif 00077 00078 __mutex_base(const __mutex_base&) = delete; 00079 __mutex_base& operator=(const __mutex_base&) = delete; 00080 }; 00081 00082 // Common base class for std::recursive_mutex and std::timed_recursive_mutex 00083 class __recursive_mutex_base 00084 { 00085 protected: 00086 typedef __gthread_recursive_mutex_t __native_type; 00087 00088 __recursive_mutex_base(const __recursive_mutex_base&) = delete; 00089 __recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete; 00090 00091 #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT 00092 __native_type _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT; 00093 00094 __recursive_mutex_base() = default; 00095 #else 00096 __native_type _M_mutex; 00097 00098 __recursive_mutex_base() 00099 { 00100 // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may) 00101 __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); 00102 } 00103 00104 ~__recursive_mutex_base() 00105 { _S_destroy(&_M_mutex); } 00106 00107 private: 00108 // FIXME: gthreads doesn't define __gthread_recursive_mutex_destroy 00109 // so we need to obtain a __gthread_mutex_t to destroy 00110 00111 // matches when there's only one mutex type 00112 template<typename _Rm> 00113 static 00114 typename enable_if<is_same<_Rm, __gthread_mutex_t>::value, void>::type 00115 _S_destroy(_Rm* __mx) 00116 { __gthread_mutex_destroy(__mx); } 00117 00118 // matches a recursive mutex with a member 'actual' 00119 template<typename _Rm> 00120 static typename enable_if<(bool)sizeof(&_Rm::actual), void>::type 00121 _S_destroy(_Rm* __mx) 00122 { __gthread_mutex_destroy(&__mx->actual); } 00123 00124 // matches a gthr-win32.h recursive mutex 00125 template<typename _Rm> 00126 static typename enable_if<(bool)sizeof(&_Rm::sema), void>::type 00127 _S_destroy(_Rm* __mx) 00128 { 00129 __gthread_mutex_t __tmp; 00130 _S_destroy_win32(&__tmp, __mx); 00131 } 00132 00133 template<typename _Mx, typename _Rm> 00134 static void 00135 _S_destroy_win32(_Mx* __mx, _Rm const* __rmx) 00136 { 00137 __mx->counter = __rmx->counter; 00138 __mx->sema = __rmx->sema; 00139 __gthread_mutex_destroy(__mx); 00140 } 00141 #endif 00142 }; 00143 00144 /** 00145 * @defgroup mutexes Mutexes 00146 * @ingroup concurrency 00147 * 00148 * Classes for mutex support. 00149 * @{ 00150 */ 00151 00152 /// mutex 00153 class mutex : private __mutex_base 00154 { 00155 public: 00156 typedef __native_type* native_handle_type; 00157 00158 #ifdef __GTHREAD_MUTEX_INIT 00159 constexpr 00160 #endif 00161 mutex() noexcept = default; 00162 ~mutex() = default; 00163 00164 mutex(const mutex&) = delete; 00165 mutex& operator=(const mutex&) = delete; 00166 00167 void 00168 lock() 00169 { 00170 int __e = __gthread_mutex_lock(&_M_mutex); 00171 00172 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 00173 if (__e) 00174 __throw_system_error(__e); 00175 } 00176 00177 bool 00178 try_lock() noexcept 00179 { 00180 // XXX EINVAL, EAGAIN, EBUSY 00181 return !__gthread_mutex_trylock(&_M_mutex); 00182 } 00183 00184 void 00185 unlock() 00186 { 00187 // XXX EINVAL, EAGAIN, EPERM 00188 __gthread_mutex_unlock(&_M_mutex); 00189 } 00190 00191 native_handle_type 00192 native_handle() 00193 { return &_M_mutex; } 00194 }; 00195 00196 /// recursive_mutex 00197 class recursive_mutex : private __recursive_mutex_base 00198 { 00199 public: 00200 typedef __native_type* native_handle_type; 00201 00202 recursive_mutex() = default; 00203 ~recursive_mutex() = default; 00204 00205 recursive_mutex(const recursive_mutex&) = delete; 00206 recursive_mutex& operator=(const recursive_mutex&) = delete; 00207 00208 void 00209 lock() 00210 { 00211 int __e = __gthread_recursive_mutex_lock(&_M_mutex); 00212 00213 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 00214 if (__e) 00215 __throw_system_error(__e); 00216 } 00217 00218 bool 00219 try_lock() noexcept 00220 { 00221 // XXX EINVAL, EAGAIN, EBUSY 00222 return !__gthread_recursive_mutex_trylock(&_M_mutex); 00223 } 00224 00225 void 00226 unlock() 00227 { 00228 // XXX EINVAL, EAGAIN, EBUSY 00229 __gthread_recursive_mutex_unlock(&_M_mutex); 00230 } 00231 00232 native_handle_type 00233 native_handle() 00234 { return &_M_mutex; } 00235 }; 00236 00237 #if _GTHREAD_USE_MUTEX_TIMEDLOCK 00238 /// timed_mutex 00239 class timed_mutex : private __mutex_base 00240 { 00241 #ifdef _GLIBCXX_USE_CLOCK_MONOTONIC 00242 typedef chrono::steady_clock __clock_t; 00243 #else 00244 typedef chrono::high_resolution_clock __clock_t; 00245 #endif 00246 00247 public: 00248 typedef __native_type* native_handle_type; 00249 00250 timed_mutex() = default; 00251 ~timed_mutex() = default; 00252 00253 timed_mutex(const timed_mutex&) = delete; 00254 timed_mutex& operator=(const timed_mutex&) = delete; 00255 00256 void 00257 lock() 00258 { 00259 int __e = __gthread_mutex_lock(&_M_mutex); 00260 00261 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 00262 if (__e) 00263 __throw_system_error(__e); 00264 } 00265 00266 bool 00267 try_lock() noexcept 00268 { 00269 // XXX EINVAL, EAGAIN, EBUSY 00270 return !__gthread_mutex_trylock(&_M_mutex); 00271 } 00272 00273 template <class _Rep, class _Period> 00274 bool 00275 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 00276 { return __try_lock_for_impl(__rtime); } 00277 00278 template <class _Clock, class _Duration> 00279 bool 00280 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 00281 { 00282 chrono::time_point<_Clock, chrono::seconds> __s = 00283 chrono::time_point_cast<chrono::seconds>(__atime); 00284 00285 chrono::nanoseconds __ns = 00286 chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 00287 00288 __gthread_time_t __ts = { 00289 static_cast<std::time_t>(__s.time_since_epoch().count()), 00290 static_cast<long>(__ns.count()) 00291 }; 00292 00293 return !__gthread_mutex_timedlock(&_M_mutex, &__ts); 00294 } 00295 00296 void 00297 unlock() 00298 { 00299 // XXX EINVAL, EAGAIN, EBUSY 00300 __gthread_mutex_unlock(&_M_mutex); 00301 } 00302 00303 native_handle_type 00304 native_handle() 00305 { return &_M_mutex; } 00306 00307 private: 00308 template<typename _Rep, typename _Period> 00309 typename enable_if< 00310 ratio_less_equal<__clock_t::period, _Period>::value, bool>::type 00311 __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime) 00312 { 00313 __clock_t::time_point __atime = __clock_t::now() 00314 + chrono::duration_cast<__clock_t::duration>(__rtime); 00315 00316 return try_lock_until(__atime); 00317 } 00318 00319 template <typename _Rep, typename _Period> 00320 typename enable_if< 00321 !ratio_less_equal<__clock_t::period, _Period>::value, bool>::type 00322 __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime) 00323 { 00324 __clock_t::time_point __atime = __clock_t::now() 00325 + ++chrono::duration_cast<__clock_t::duration>(__rtime); 00326 00327 return try_lock_until(__atime); 00328 } 00329 }; 00330 00331 /// recursive_timed_mutex 00332 class recursive_timed_mutex : private __recursive_mutex_base 00333 { 00334 #ifdef _GLIBCXX_USE_CLOCK_MONOTONIC 00335 typedef chrono::steady_clock __clock_t; 00336 #else 00337 typedef chrono::high_resolution_clock __clock_t; 00338 #endif 00339 00340 public: 00341 typedef __native_type* native_handle_type; 00342 00343 recursive_timed_mutex() = default; 00344 ~recursive_timed_mutex() = default; 00345 00346 recursive_timed_mutex(const recursive_timed_mutex&) = delete; 00347 recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; 00348 00349 void 00350 lock() 00351 { 00352 int __e = __gthread_recursive_mutex_lock(&_M_mutex); 00353 00354 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 00355 if (__e) 00356 __throw_system_error(__e); 00357 } 00358 00359 bool 00360 try_lock() noexcept 00361 { 00362 // XXX EINVAL, EAGAIN, EBUSY 00363 return !__gthread_recursive_mutex_trylock(&_M_mutex); 00364 } 00365 00366 template <class _Rep, class _Period> 00367 bool 00368 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 00369 { return __try_lock_for_impl(__rtime); } 00370 00371 template <class _Clock, class _Duration> 00372 bool 00373 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 00374 { 00375 chrono::time_point<_Clock, chrono::seconds> __s = 00376 chrono::time_point_cast<chrono::seconds>(__atime); 00377 00378 chrono::nanoseconds __ns = 00379 chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 00380 00381 __gthread_time_t __ts = { 00382 static_cast<std::time_t>(__s.time_since_epoch().count()), 00383 static_cast<long>(__ns.count()) 00384 }; 00385 00386 return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts); 00387 } 00388 00389 void 00390 unlock() 00391 { 00392 // XXX EINVAL, EAGAIN, EBUSY 00393 __gthread_recursive_mutex_unlock(&_M_mutex); 00394 } 00395 00396 native_handle_type 00397 native_handle() 00398 { return &_M_mutex; } 00399 00400 private: 00401 template<typename _Rep, typename _Period> 00402 typename enable_if< 00403 ratio_less_equal<__clock_t::period, _Period>::value, bool>::type 00404 __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime) 00405 { 00406 __clock_t::time_point __atime = __clock_t::now() 00407 + chrono::duration_cast<__clock_t::duration>(__rtime); 00408 00409 return try_lock_until(__atime); 00410 } 00411 00412 template <typename _Rep, typename _Period> 00413 typename enable_if< 00414 !ratio_less_equal<__clock_t::period, _Period>::value, bool>::type 00415 __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime) 00416 { 00417 __clock_t::time_point __atime = __clock_t::now() 00418 + ++chrono::duration_cast<__clock_t::duration>(__rtime); 00419 00420 return try_lock_until(__atime); 00421 } 00422 }; 00423 #endif 00424 #endif // _GLIBCXX_HAS_GTHREADS 00425 00426 /// Do not acquire ownership of the mutex. 00427 struct defer_lock_t { }; 00428 00429 /// Try to acquire ownership of the mutex without blocking. 00430 struct try_to_lock_t { }; 00431 00432 /// Assume the calling thread has already obtained mutex ownership 00433 /// and manage it. 00434 struct adopt_lock_t { }; 00435 00436 constexpr defer_lock_t defer_lock { }; 00437 constexpr try_to_lock_t try_to_lock { }; 00438 constexpr adopt_lock_t adopt_lock { }; 00439 00440 /// @brief Scoped lock idiom. 00441 // Acquire the mutex here with a constructor call, then release with 00442 // the destructor call in accordance with RAII style. 00443 template<typename _Mutex> 00444 class lock_guard 00445 { 00446 public: 00447 typedef _Mutex mutex_type; 00448 00449 explicit lock_guard(mutex_type& __m) : _M_device(__m) 00450 { _M_device.lock(); } 00451 00452 lock_guard(mutex_type& __m, adopt_lock_t) : _M_device(__m) 00453 { } // calling thread owns mutex 00454 00455 ~lock_guard() 00456 { _M_device.unlock(); } 00457 00458 lock_guard(const lock_guard&) = delete; 00459 lock_guard& operator=(const lock_guard&) = delete; 00460 00461 private: 00462 mutex_type& _M_device; 00463 }; 00464 00465 /// unique_lock 00466 template<typename _Mutex> 00467 class unique_lock 00468 { 00469 public: 00470 typedef _Mutex mutex_type; 00471 00472 unique_lock() noexcept 00473 : _M_device(0), _M_owns(false) 00474 { } 00475 00476 explicit unique_lock(mutex_type& __m) 00477 : _M_device(&__m), _M_owns(false) 00478 { 00479 lock(); 00480 _M_owns = true; 00481 } 00482 00483 unique_lock(mutex_type& __m, defer_lock_t) noexcept 00484 : _M_device(&__m), _M_owns(false) 00485 { } 00486 00487 unique_lock(mutex_type& __m, try_to_lock_t) 00488 : _M_device(&__m), _M_owns(_M_device->try_lock()) 00489 { } 00490 00491 unique_lock(mutex_type& __m, adopt_lock_t) 00492 : _M_device(&__m), _M_owns(true) 00493 { 00494 // XXX calling thread owns mutex 00495 } 00496 00497 template<typename _Clock, typename _Duration> 00498 unique_lock(mutex_type& __m, 00499 const chrono::time_point<_Clock, _Duration>& __atime) 00500 : _M_device(&__m), _M_owns(_M_device->try_lock_until(__atime)) 00501 { } 00502 00503 template<typename _Rep, typename _Period> 00504 unique_lock(mutex_type& __m, 00505 const chrono::duration<_Rep, _Period>& __rtime) 00506 : _M_device(&__m), _M_owns(_M_device->try_lock_for(__rtime)) 00507 { } 00508 00509 ~unique_lock() 00510 { 00511 if (_M_owns) 00512 unlock(); 00513 } 00514 00515 unique_lock(const unique_lock&) = delete; 00516 unique_lock& operator=(const unique_lock&) = delete; 00517 00518 unique_lock(unique_lock&& __u) noexcept 00519 : _M_device(__u._M_device), _M_owns(__u._M_owns) 00520 { 00521 __u._M_device = 0; 00522 __u._M_owns = false; 00523 } 00524 00525 unique_lock& operator=(unique_lock&& __u) noexcept 00526 { 00527 if(_M_owns) 00528 unlock(); 00529 00530 unique_lock(std::move(__u)).swap(*this); 00531 00532 __u._M_device = 0; 00533 __u._M_owns = false; 00534 00535 return *this; 00536 } 00537 00538 void 00539 lock() 00540 { 00541 if (!_M_device) 00542 __throw_system_error(int(errc::operation_not_permitted)); 00543 else if (_M_owns) 00544 __throw_system_error(int(errc::resource_deadlock_would_occur)); 00545 else 00546 { 00547 _M_device->lock(); 00548 _M_owns = true; 00549 } 00550 } 00551 00552 bool 00553 try_lock() 00554 { 00555 if (!_M_device) 00556 __throw_system_error(int(errc::operation_not_permitted)); 00557 else if (_M_owns) 00558 __throw_system_error(int(errc::resource_deadlock_would_occur)); 00559 else 00560 { 00561 _M_owns = _M_device->try_lock(); 00562 return _M_owns; 00563 } 00564 } 00565 00566 template<typename _Clock, typename _Duration> 00567 bool 00568 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 00569 { 00570 if (!_M_device) 00571 __throw_system_error(int(errc::operation_not_permitted)); 00572 else if (_M_owns) 00573 __throw_system_error(int(errc::resource_deadlock_would_occur)); 00574 else 00575 { 00576 _M_owns = _M_device->try_lock_until(__atime); 00577 return _M_owns; 00578 } 00579 } 00580 00581 template<typename _Rep, typename _Period> 00582 bool 00583 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 00584 { 00585 if (!_M_device) 00586 __throw_system_error(int(errc::operation_not_permitted)); 00587 else if (_M_owns) 00588 __throw_system_error(int(errc::resource_deadlock_would_occur)); 00589 else 00590 { 00591 _M_owns = _M_device->try_lock_for(__rtime); 00592 return _M_owns; 00593 } 00594 } 00595 00596 void 00597 unlock() 00598 { 00599 if (!_M_owns) 00600 __throw_system_error(int(errc::operation_not_permitted)); 00601 else if (_M_device) 00602 { 00603 _M_device->unlock(); 00604 _M_owns = false; 00605 } 00606 } 00607 00608 void 00609 swap(unique_lock& __u) noexcept 00610 { 00611 std::swap(_M_device, __u._M_device); 00612 std::swap(_M_owns, __u._M_owns); 00613 } 00614 00615 mutex_type* 00616 release() noexcept 00617 { 00618 mutex_type* __ret = _M_device; 00619 _M_device = 0; 00620 _M_owns = false; 00621 return __ret; 00622 } 00623 00624 bool 00625 owns_lock() const noexcept 00626 { return _M_owns; } 00627 00628 explicit operator bool() const noexcept 00629 { return owns_lock(); } 00630 00631 mutex_type* 00632 mutex() const noexcept 00633 { return _M_device; } 00634 00635 private: 00636 mutex_type* _M_device; 00637 bool _M_owns; // XXX use atomic_bool 00638 }; 00639 00640 /// Partial specialization for unique_lock objects. 00641 template<typename _Mutex> 00642 inline void 00643 swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) noexcept 00644 { __x.swap(__y); } 00645 00646 template<int _Idx> 00647 struct __unlock_impl 00648 { 00649 template<typename... _Lock> 00650 static void 00651 __do_unlock(tuple<_Lock&...>& __locks) 00652 { 00653 std::get<_Idx>(__locks).unlock(); 00654 __unlock_impl<_Idx - 1>::__do_unlock(__locks); 00655 } 00656 }; 00657 00658 template<> 00659 struct __unlock_impl<-1> 00660 { 00661 template<typename... _Lock> 00662 static void 00663 __do_unlock(tuple<_Lock&...>&) 00664 { } 00665 }; 00666 00667 template<typename _Lock> 00668 unique_lock<_Lock> 00669 __try_to_lock(_Lock& __l) 00670 { return unique_lock<_Lock>(__l, try_to_lock); } 00671 00672 template<int _Idx, bool _Continue = true> 00673 struct __try_lock_impl 00674 { 00675 template<typename... _Lock> 00676 static void 00677 __do_try_lock(tuple<_Lock&...>& __locks, int& __idx) 00678 { 00679 __idx = _Idx; 00680 auto __lock = __try_to_lock(std::get<_Idx>(__locks)); 00681 if (__lock.owns_lock()) 00682 { 00683 __try_lock_impl<_Idx + 1, _Idx + 2 < sizeof...(_Lock)>:: 00684 __do_try_lock(__locks, __idx); 00685 if (__idx == -1) 00686 __lock.release(); 00687 } 00688 } 00689 }; 00690 00691 template<int _Idx> 00692 struct __try_lock_impl<_Idx, false> 00693 { 00694 template<typename... _Lock> 00695 static void 00696 __do_try_lock(tuple<_Lock&...>& __locks, int& __idx) 00697 { 00698 __idx = _Idx; 00699 auto __lock = __try_to_lock(std::get<_Idx>(__locks)); 00700 if (__lock.owns_lock()) 00701 { 00702 __idx = -1; 00703 __lock.release(); 00704 } 00705 } 00706 }; 00707 00708 /** @brief Generic try_lock. 00709 * @param __l1 Meets Mutex requirements (try_lock() may throw). 00710 * @param __l2 Meets Mutex requirements (try_lock() may throw). 00711 * @param __l3 Meets Mutex requirements (try_lock() may throw). 00712 * @return Returns -1 if all try_lock() calls return true. Otherwise returns 00713 * a 0-based index corresponding to the argument that returned false. 00714 * @post Either all arguments are locked, or none will be. 00715 * 00716 * Sequentially calls try_lock() on each argument. 00717 */ 00718 template<typename _Lock1, typename _Lock2, typename... _Lock3> 00719 int 00720 try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3) 00721 { 00722 int __idx; 00723 auto __locks = std::tie(__l1, __l2, __l3...); 00724 __try 00725 { __try_lock_impl<0>::__do_try_lock(__locks, __idx); } 00726 __catch(...) 00727 { } 00728 return __idx; 00729 } 00730 00731 /** @brief Generic lock. 00732 * @param __l1 Meets Mutex requirements (try_lock() may throw). 00733 * @param __l2 Meets Mutex requirements (try_lock() may throw). 00734 * @param __l3 Meets Mutex requirements (try_lock() may throw). 00735 * @throw An exception thrown by an argument's lock() or try_lock() member. 00736 * @post All arguments are locked. 00737 * 00738 * All arguments are locked via a sequence of calls to lock(), try_lock() 00739 * and unlock(). If the call exits via an exception any locks that were 00740 * obtained will be released. 00741 */ 00742 template<typename _L1, typename _L2, typename ..._L3> 00743 void 00744 lock(_L1& __l1, _L2& __l2, _L3&... __l3) 00745 { 00746 while (true) 00747 { 00748 unique_lock<_L1> __first(__l1); 00749 int __idx; 00750 auto __locks = std::tie(__l2, __l3...); 00751 __try_lock_impl<0, sizeof...(_L3)>::__do_try_lock(__locks, __idx); 00752 if (__idx == -1) 00753 { 00754 __first.release(); 00755 return; 00756 } 00757 } 00758 } 00759 00760 #ifdef _GLIBCXX_HAS_GTHREADS 00761 /// once_flag 00762 struct once_flag 00763 { 00764 private: 00765 typedef __gthread_once_t __native_type; 00766 __native_type _M_once = __GTHREAD_ONCE_INIT; 00767 00768 public: 00769 /// Constructor 00770 constexpr once_flag() noexcept = default; 00771 00772 /// Deleted copy constructor 00773 once_flag(const once_flag&) = delete; 00774 /// Deleted assignment operator 00775 once_flag& operator=(const once_flag&) = delete; 00776 00777 template<typename _Callable, typename... _Args> 00778 friend void 00779 call_once(once_flag& __once, _Callable&& __f, _Args&&... __args); 00780 }; 00781 00782 #ifdef _GLIBCXX_HAVE_TLS 00783 extern __thread void* __once_callable; 00784 extern __thread void (*__once_call)(); 00785 00786 template<typename _Callable> 00787 inline void 00788 __once_call_impl() 00789 { 00790 (*(_Callable*)__once_callable)(); 00791 } 00792 #else 00793 extern function<void()> __once_functor; 00794 00795 extern void 00796 __set_once_functor_lock_ptr(unique_lock<mutex>*); 00797 00798 extern mutex& 00799 __get_once_mutex(); 00800 #endif 00801 00802 extern "C" void __once_proxy(void); 00803 00804 /// call_once 00805 template<typename _Callable, typename... _Args> 00806 void 00807 call_once(once_flag& __once, _Callable&& __f, _Args&&... __args) 00808 { 00809 #ifdef _GLIBCXX_HAVE_TLS 00810 auto __bound_functor = std::__bind_simple(std::forward<_Callable>(__f), 00811 std::forward<_Args>(__args)...); 00812 __once_callable = &__bound_functor; 00813 __once_call = &__once_call_impl<decltype(__bound_functor)>; 00814 #else 00815 unique_lock<mutex> __functor_lock(__get_once_mutex()); 00816 auto __callable = std::__bind_simple(std::forward<_Callable>(__f), 00817 std::forward<_Args>(__args)...); 00818 __once_functor = [&]() { __callable(); }; 00819 __set_once_functor_lock_ptr(&__functor_lock); 00820 #endif 00821 00822 int __e = __gthread_once(&(__once._M_once), &__once_proxy); 00823 00824 #ifndef _GLIBCXX_HAVE_TLS 00825 if (__functor_lock) 00826 __set_once_functor_lock_ptr(0); 00827 #endif 00828 00829 if (__e) 00830 __throw_system_error(__e); 00831 } 00832 #endif // _GLIBCXX_HAS_GTHREADS 00833 00834 // @} group mutexes 00835 _GLIBCXX_END_NAMESPACE_VERSION 00836 } // namespace 00837 00838 #endif // _GLIBCXX_USE_C99_STDINT_TR1 00839 00840 #endif // __GXX_EXPERIMENTAL_CXX0X__ 00841 00842 #endif // _GLIBCXX_MUTEX