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