108 KiB
108 KiB
<html lang="en">
<head>
</head>
</html>
LCOV - code coverage report | ||||||||||||||||||||||
![]() | ||||||||||||||||||||||
|
||||||||||||||||||||||
![]() |
Line data Source code 1 : // <mutex> -*- C++ -*- 2 : 3 : // Copyright (C) 2003-2023 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 : #include <bits/requires_hosted.h> // concurrency 35 : 36 : #if __cplusplus < 201103L 37 : # include <bits/c++0x_warning.h> 38 : #else 39 : 40 : #include <tuple> 41 : #include <exception> 42 : #include <type_traits> 43 : #include <bits/chrono.h> 44 : #include <bits/error_constants.h> 45 : #include <bits/std_mutex.h> 46 : #include <bits/unique_lock.h> 47 : #if ! _GTHREAD_USE_MUTEX_TIMEDLOCK 48 : # include <condition_variable> 49 : # include <thread> 50 : #endif 51 : #include <ext/atomicity.h> // __gnu_cxx::__is_single_threaded 52 : 53 : #if defined _GLIBCXX_HAS_GTHREADS && ! defined _GLIBCXX_HAVE_TLS 54 : # include <bits/std_function.h> // std::function 55 : #endif 56 : 57 : namespace std _GLIBCXX_VISIBILITY(default) 58 : { 59 : _GLIBCXX_BEGIN_NAMESPACE_VERSION 60 : 61 : /** 62 : * @addtogroup mutexes 63 : * @{ 64 : */ 65 : 66 : #ifdef _GLIBCXX_HAS_GTHREADS 67 : /// @cond undocumented 68 : 69 : // Common base class for std::recursive_mutex and std::recursive_timed_mutex 70 : class __recursive_mutex_base 71 : { 72 : protected: 73 : typedef __gthread_recursive_mutex_t __native_type; 74 : 75 : __recursive_mutex_base(const __recursive_mutex_base&) = delete; 76 : __recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete; 77 : 78 : #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT 79 : __native_type _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT; 80 : 81 : __recursive_mutex_base() = default; 82 : #else 83 : __native_type _M_mutex; 84 : 85 : __recursive_mutex_base() 86 : { 87 : // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may) 88 : __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); 89 : } 90 : 91 : ~__recursive_mutex_base() 92 : { __gthread_recursive_mutex_destroy(&_M_mutex); } 93 : #endif 94 : }; 95 : /// @endcond 96 : 97 : /** The standard recursive mutex type. 98 : * 99 : * A recursive mutex can be locked more than once by the same thread. 100 : * Other threads cannot lock the mutex until the owning thread unlocks it 101 : * as many times as it was locked. 102 : * 103 : * @headerfile mutex 104 : * @since C++11 105 : */ 106 : class recursive_mutex : private __recursive_mutex_base 107 : { 108 : public: 109 : typedef __native_type* native_handle_type; 110 : 111 : recursive_mutex() = default; 112 : ~recursive_mutex() = default; 113 : 114 : recursive_mutex(const recursive_mutex&) = delete; 115 : recursive_mutex& operator=(const recursive_mutex&) = delete; 116 : 117 : void 118 3564 : lock() 119 : { 120 3564 : int __e = __gthread_recursive_mutex_lock(&_M_mutex); 121 : 122 : // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 123 3564 : if (__e) 124 0 : __throw_system_error(__e); 125 3564 : } 126 : 127 : _GLIBCXX_NODISCARD 128 : bool 129 : try_lock() noexcept 130 : { 131 : // XXX EINVAL, EAGAIN, EBUSY 132 : return !__gthread_recursive_mutex_trylock(&_M_mutex); 133 : } 134 : 135 : void 136 3564 : unlock() 137 : { 138 : // XXX EINVAL, EAGAIN, EBUSY 139 3564 : __gthread_recursive_mutex_unlock(&_M_mutex); 140 3564 : } 141 : 142 : native_handle_type 143 : native_handle() noexcept 144 : { return &_M_mutex; } 145 : }; 146 : 147 : #if _GTHREAD_USE_MUTEX_TIMEDLOCK 148 : /// @cond undocumented 149 : 150 : template<typename _Derived> 151 : class __timed_mutex_impl 152 : { 153 : protected: 154 : template<typename _Rep, typename _Period> 155 : bool 156 : _M_try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 157 : { 158 : #if _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK 159 : using __clock = chrono::steady_clock; 160 : #else 161 : using __clock = chrono::system_clock; 162 : #endif 163 : 164 : auto __rt = chrono::duration_cast<__clock::duration>(__rtime); 165 : if (ratio_greater<__clock::period, _Period>()) 166 : ++__rt; 167 : return _M_try_lock_until(__clock::now() + __rt); 168 : } 169 : 170 : template<typename _Duration> 171 : bool 172 : _M_try_lock_until(const chrono::time_point<chrono::system_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_timedlock(__ts); 184 : } 185 : 186 : #ifdef _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK 187 : template<typename _Duration> 188 : bool 189 : _M_try_lock_until(const chrono::time_point<chrono::steady_clock, 190 : _Duration>& __atime) 191 : { 192 : auto __s = chrono::time_point_cast<chrono::seconds>(__atime); 193 : auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 194 : 195 : __gthread_time_t __ts = { 196 : static_cast<std::time_t>(__s.time_since_epoch().count()), 197 : static_cast<long>(__ns.count()) 198 : }; 199 : 200 : return static_cast<_Derived*>(this)->_M_clocklock(CLOCK_MONOTONIC, 201 : __ts); 202 : } 203 : #endif 204 : 205 : template<typename _Clock, typename _Duration> 206 : bool 207 : _M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 208 : { 209 : #if __cplusplus > 201703L 210 : static_assert(chrono::is_clock_v<_Clock>); 211 : #endif 212 : // The user-supplied clock may not tick at the same rate as 213 : // steady_clock, so we must loop in order to guarantee that 214 : // the timeout has expired before returning false. 215 : auto __now = _Clock::now(); 216 : do { 217 : auto __rtime = __atime - __now; 218 : if (_M_try_lock_for(__rtime)) 219 : return true; 220 : __now = _Clock::now(); 221 : } while (__atime > __now); 222 : return false; 223 : } 224 : }; 225 : /// @endcond 226 : 227 : /** The standard timed mutex type. 228 : * 229 : * A non-recursive mutex that supports a timeout when trying to acquire the 230 : * lock. 231 : * 232 : * @headerfile mutex 233 : * @since C++11 234 : */ 235 : class timed_mutex 236 : : private __mutex_base, public __timed_mutex_impl<timed_mutex> 237 : { 238 : public: 239 : typedef __native_type* native_handle_type; 240 : 241 : timed_mutex() = default; 242 : ~timed_mutex() = default; 243 : 244 : timed_mutex(const timed_mutex&) = delete; 245 : timed_mutex& operator=(const timed_mutex&) = delete; 246 : 247 : void 248 : lock() 249 : { 250 : int __e = __gthread_mutex_lock(&_M_mutex); 251 : 252 : // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 253 : if (__e) 254 : __throw_system_error(__e); 255 : } 256 : 257 : _GLIBCXX_NODISCARD 258 : bool 259 : try_lock() noexcept 260 : { 261 : // XXX EINVAL, EAGAIN, EBUSY 262 : return !__gthread_mutex_trylock(&_M_mutex); 263 : } 264 : 265 : template <class _Rep, class _Period> 266 : _GLIBCXX_NODISCARD 267 : bool 268 : try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 269 : { return _M_try_lock_for(__rtime); } 270 : 271 : template <class _Clock, class _Duration> 272 : _GLIBCXX_NODISCARD 273 : bool 274 : try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 275 : { return _M_try_lock_until(__atime); } 276 : 277 : void 278 : unlock() 279 : { 280 : // XXX EINVAL, EAGAIN, EBUSY 281 : __gthread_mutex_unlock(&_M_mutex); 282 : } 283 : 284 : native_handle_type 285 : native_handle() noexcept 286 : { return &_M_mutex; } 287 : 288 : private: 289 : friend class __timed_mutex_impl<timed_mutex>; 290 : 291 : bool 292 : _M_timedlock(const __gthread_time_t& __ts) 293 : { return !__gthread_mutex_timedlock(&_M_mutex, &__ts); } 294 : 295 : #if _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK 296 : bool 297 : _M_clocklock(clockid_t __clockid, const __gthread_time_t& __ts) 298 : { return !pthread_mutex_clocklock(&_M_mutex, __clockid, &__ts); } 299 : #endif 300 : }; 301 : 302 : /** The standard recursive timed mutex type. 303 : * 304 : * A recursive mutex that supports a timeout when trying to acquire the 305 : * lock. A recursive mutex can be locked more than once by the same thread. 306 : * Other threads cannot lock the mutex until the owning thread unlocks it 307 : * as many times as it was locked. 308 : * 309 : * @headerfile mutex 310 : * @since C++11 311 : */ 312 : class recursive_timed_mutex 313 : : private __recursive_mutex_base, 314 : public __timed_mutex_impl<recursive_timed_mutex> 315 : { 316 : public: 317 : typedef __native_type* native_handle_type; 318 : 319 : recursive_timed_mutex() = default; 320 : ~recursive_timed_mutex() = default; 321 : 322 : recursive_timed_mutex(const recursive_timed_mutex&) = delete; 323 : recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; 324 : 325 : void 326 : lock() 327 : { 328 : int __e = __gthread_recursive_mutex_lock(&_M_mutex); 329 : 330 : // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 331 : if (__e) 332 : __throw_system_error(__e); 333 : } 334 : 335 : _GLIBCXX_NODISCARD 336 : bool 337 : try_lock() noexcept 338 : { 339 : // XXX EINVAL, EAGAIN, EBUSY 340 : return !__gthread_recursive_mutex_trylock(&_M_mutex); 341 : } 342 : 343 : template <class _Rep, class _Period> 344 : _GLIBCXX_NODISCARD 345 : bool 346 : try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 347 : { return _M_try_lock_for(__rtime); } 348 : 349 : template <class _Clock, class _Duration> 350 : _GLIBCXX_NODISCARD 351 : bool 352 : try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 353 : { return _M_try_lock_until(__atime); } 354 : 355 : void 356 : unlock() 357 : { 358 : // XXX EINVAL, EAGAIN, EBUSY 359 : __gthread_recursive_mutex_unlock(&_M_mutex); 360 : } 361 : 362 : native_handle_type 363 : native_handle() noexcept 364 : { return &_M_mutex; } 365 : 366 : private: 367 : friend class __timed_mutex_impl<recursive_timed_mutex>; 368 : 369 : bool 370 : _M_timedlock(const __gthread_time_t& __ts) 371 : { return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts); } 372 : 373 : #ifdef _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK 374 : bool 375 : _M_clocklock(clockid_t __clockid, const __gthread_time_t& __ts) 376 : { return !pthread_mutex_clocklock(&_M_mutex, __clockid, &__ts); } 377 : #endif 378 : }; 379 : 380 : #else // !_GTHREAD_USE_MUTEX_TIMEDLOCK 381 : 382 : /// timed_mutex 383 : class timed_mutex 384 : { 385 : mutex _M_mut; 386 : condition_variable _M_cv; 387 : bool _M_locked = false; 388 : 389 : public: 390 : 391 : timed_mutex() = default; 392 : ~timed_mutex() { __glibcxx_assert( !_M_locked ); } 393 : 394 : timed_mutex(const timed_mutex&) = delete; 395 : timed_mutex& operator=(const timed_mutex&) = delete; 396 : 397 : void 398 : lock() 399 : { 400 : unique_lock<mutex> __lk(_M_mut); 401 : _M_cv.wait(__lk, [&]{ return !_M_locked; }); 402 : _M_locked = true; 403 : } 404 : 405 : _GLIBCXX_NODISCARD 406 : bool 407 : try_lock() 408 : { 409 : lock_guard<mutex> __lk(_M_mut); 410 : if (_M_locked) 411 : return false; 412 : _M_locked = true; 413 : return true; 414 : } 415 : 416 : template<typename _Rep, typename _Period> 417 : _GLIBCXX_NODISCARD 418 : bool 419 : try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 420 : { 421 : unique_lock<mutex> __lk(_M_mut); 422 : if (!_M_cv.wait_for(__lk, __rtime, [&]{ return !_M_locked; })) 423 : return false; 424 : _M_locked = true; 425 : return true; 426 : } 427 : 428 : template<typename _Clock, typename _Duration> 429 : _GLIBCXX_NODISCARD 430 : bool 431 : try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 432 : { 433 : unique_lock<mutex> __lk(_M_mut); 434 : if (!_M_cv.wait_until(__lk, __atime, [&]{ return !_M_locked; })) 435 : return false; 436 : _M_locked = true; 437 : return true; 438 : } 439 : 440 : void 441 : unlock() 442 : { 443 : lock_guard<mutex> __lk(_M_mut); 444 : __glibcxx_assert( _M_locked ); 445 : _M_locked = false; 446 : _M_cv.notify_one(); 447 : } 448 : }; 449 : 450 : /// recursive_timed_mutex 451 : class recursive_timed_mutex 452 : { 453 : mutex _M_mut; 454 : condition_variable _M_cv; 455 : thread::id _M_owner; 456 : unsigned _M_count = 0; 457 : 458 : // Predicate type that tests whether the current thread can lock a mutex. 459 : struct _Can_lock 460 : { 461 : // Returns true if the mutex is unlocked or is locked by _M_caller. 462 : bool 463 : operator()() const noexcept 464 : { return _M_mx->_M_count == 0 || _M_mx->_M_owner == _M_caller; } 465 : 466 : const recursive_timed_mutex* _M_mx; 467 : thread::id _M_caller; 468 : }; 469 : 470 : public: 471 : 472 : recursive_timed_mutex() = default; 473 : ~recursive_timed_mutex() { __glibcxx_assert( _M_count == 0 ); } 474 : 475 : recursive_timed_mutex(const recursive_timed_mutex&) = delete; 476 : recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; 477 : 478 : void 479 : lock() 480 : { 481 : auto __id = this_thread::get_id(); 482 : _Can_lock __can_lock{this, __id}; 483 : unique_lock<mutex> __lk(_M_mut); 484 : _M_cv.wait(__lk, __can_lock); 485 : if (_M_count == -1u) 486 : __throw_system_error(EAGAIN); // [thread.timedmutex.recursive]/3 487 : _M_owner = __id; 488 : ++_M_count; 489 : } 490 : 491 : _GLIBCXX_NODISCARD 492 : bool 493 : try_lock() 494 : { 495 : auto __id = this_thread::get_id(); 496 : _Can_lock __can_lock{this, __id}; 497 : lock_guard<mutex> __lk(_M_mut); 498 : if (!__can_lock()) 499 : return false; 500 : if (_M_count == -1u) 501 : return false; 502 : _M_owner = __id; 503 : ++_M_count; 504 : return true; 505 : } 506 : 507 : template<typename _Rep, typename _Period> 508 : _GLIBCXX_NODISCARD 509 : bool 510 : try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 511 : { 512 : auto __id = this_thread::get_id(); 513 : _Can_lock __can_lock{this, __id}; 514 : unique_lock<mutex> __lk(_M_mut); 515 : if (!_M_cv.wait_for(__lk, __rtime, __can_lock)) 516 : return false; 517 : if (_M_count == -1u) 518 : return false; 519 : _M_owner = __id; 520 : ++_M_count; 521 : return true; 522 : } 523 : 524 : template<typename _Clock, typename _Duration> 525 : _GLIBCXX_NODISCARD 526 : bool 527 : try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 528 : { 529 : auto __id = this_thread::get_id(); 530 : _Can_lock __can_lock{this, __id}; 531 : unique_lock<mutex> __lk(_M_mut); 532 : if (!_M_cv.wait_until(__lk, __atime, __can_lock)) 533 : return false; 534 : if (_M_count == -1u) 535 : return false; 536 : _M_owner = __id; 537 : ++_M_count; 538 : return true; 539 : } 540 : 541 : void 542 : unlock() 543 : { 544 : lock_guard<mutex> __lk(_M_mut); 545 : __glibcxx_assert( _M_owner == this_thread::get_id() ); 546 : __glibcxx_assert( _M_count > 0 ); 547 : if (--_M_count == 0) 548 : { 549 : _M_owner = {}; 550 : _M_cv.notify_one(); 551 : } 552 : } 553 : }; 554 : 555 : #endif 556 : #endif // _GLIBCXX_HAS_GTHREADS 557 : 558 : /// @cond undocumented 559 : namespace __detail 560 : { 561 : // Lock the last lockable, after all previous ones are locked. 562 : template<typename _Lockable> 563 : inline int 564 : __try_lock_impl(_Lockable& __l) 565 : { 566 : if (unique_lock<_Lockable> __lock{__l, try_to_lock}) 567 : { 568 : __lock.release(); 569 : return -1; 570 : } 571 : else 572 : return 0; 573 : } 574 : 575 : // Lock each lockable in turn. 576 : // Use iteration if all lockables are the same type, recursion otherwise. 577 : template<typename _L0, typename... _Lockables> 578 : inline int 579 : __try_lock_impl(_L0& __l0, _Lockables&... __lockables) 580 : { 581 : #if __cplusplus >= 201703L 582 : if constexpr ((is_same_v<_L0, _Lockables> && ...)) 583 : { 584 : constexpr int _Np = 1 + sizeof...(_Lockables); 585 : unique_lock<_L0> __locks[_Np] = { 586 : {__l0, defer_lock}, {__lockables, defer_lock}... 587 : }; 588 : for (int __i = 0; __i < _Np; ++__i) 589 : { 590 : if (!__locks[__i].try_lock()) 591 : { 592 : const int __failed = __i; 593 : while (__i--) 594 : __locks[__i].unlock(); 595 : return __failed; 596 : } 597 : } 598 : for (auto& __l : __locks) 599 : __l.release(); 600 : return -1; 601 : } 602 : else 603 : #endif 604 : if (unique_lock<_L0> __lock{__l0, try_to_lock}) 605 : { 606 : int __idx = __detail::__try_lock_impl(__lockables...); 607 : if (__idx == -1) 608 : { 609 : __lock.release(); 610 : return -1; 611 : } 612 : return __idx + 1; 613 : } 614 : else 615 : return 0; 616 : } 617 : 618 : } // namespace __detail 619 : /// @endcond 620 : 621 : /** @brief Generic try_lock. 622 : * @param __l1 Meets Lockable requirements (try_lock() may throw). 623 : * @param __l2 Meets Lockable requirements (try_lock() may throw). 624 : * @param __l3 Meets Lockable requirements (try_lock() may throw). 625 : * @return Returns -1 if all try_lock() calls return true. Otherwise returns 626 : * a 0-based index corresponding to the argument that returned false. 627 : * @post Either all arguments are locked, or none will be. 628 : * 629 : * Sequentially calls try_lock() on each argument. 630 : */ 631 : template<typename _L1, typename _L2, typename... _L3> 632 : _GLIBCXX_NODISCARD 633 : inline int 634 : try_lock(_L1& __l1, _L2& __l2, _L3&... __l3) 635 : { 636 : return __detail::__try_lock_impl(__l1, __l2, __l3...); 637 : } 638 : 639 : /// @cond undocumented 640 : namespace __detail 641 : { 642 : // This function can recurse up to N levels deep, for N = 1+sizeof...(L1). 643 : // On each recursion the lockables are rotated left one position, 644 : // e.g. depth 0: l0, l1, l2; depth 1: l1, l2, l0; depth 2: l2, l0, l1. 645 : // When a call to l_i.try_lock() fails it recurses/returns to depth=i 646 : // so that l_i is the first argument, and then blocks until l_i is locked. 647 : template<typename _L0, typename... _L1> 648 : void 649 : __lock_impl(int& __i, int __depth, _L0& __l0, _L1&... __l1) 650 : { 651 : while (__i >= __depth) 652 : { 653 : if (__i == __depth) 654 : { 655 : int __failed = 1; // index that couldn't be locked 656 : { 657 : unique_lock<_L0> __first(__l0); 658 : __failed += __detail::__try_lock_impl(__l1...); 659 : if (!__failed) 660 : { 661 : __i = -1; // finished 662 : __first.release(); 663 : return; 664 : } 665 : } 666 : #if defined _GLIBCXX_HAS_GTHREADS && defined _GLIBCXX_USE_SCHED_YIELD 667 : __gthread_yield(); 668 : #endif 669 : constexpr auto __n = 1 + sizeof...(_L1); 670 : __i = (__depth + __failed) % __n; 671 : } 672 : else // rotate left until l_i is first. 673 : __detail::__lock_impl(__i, __depth + 1, __l1..., __l0); 674 : } 675 : } 676 : 677 : } // namespace __detail 678 : /// @endcond 679 : 680 : /** @brief Generic lock. 681 : * @param __l1 Meets Lockable requirements (try_lock() may throw). 682 : * @param __l2 Meets Lockable requirements (try_lock() may throw). 683 : * @param __l3 Meets Lockable requirements (try_lock() may throw). 684 : * @throw An exception thrown by an argument's lock() or try_lock() member. 685 : * @post All arguments are locked. 686 : * 687 : * All arguments are locked via a sequence of calls to lock(), try_lock() 688 : * and unlock(). If this function exits via an exception any locks that 689 : * were obtained will be released. 690 : */ 691 : template<typename _L1, typename _L2, typename... _L3> 692 : void 693 : lock(_L1& __l1, _L2& __l2, _L3&... __l3) 694 : { 695 : #if __cplusplus >= 201703L 696 : if constexpr (is_same_v<_L1, _L2> && (is_same_v<_L1, _L3> && ...)) 697 : { 698 : constexpr int _Np = 2 + sizeof...(_L3); 699 : unique_lock<_L1> __locks[] = { 700 : {__l1, defer_lock}, {__l2, defer_lock}, {__l3, defer_lock}... 701 : }; 702 : int __first = 0; 703 : do { 704 : __locks[__first].lock(); 705 : for (int __j = 1; __j < _Np; ++__j) 706 : { 707 : const int __idx = (__first + __j) % _Np; 708 : if (!__locks[__idx].try_lock()) 709 : { 710 : for (int __k = __j; __k != 0; --__k) 711 : __locks[(__first + __k - 1) % _Np].unlock(); 712 : __first = __idx; 713 : break; 714 : } 715 : } 716 : } while (!__locks[__first].owns_lock()); 717 : 718 : for (auto& __l : __locks) 719 : __l.release(); 720 : } 721 : else 722 : #endif 723 : { 724 : int __i = 0; 725 : __detail::__lock_impl(__i, 0, __l1, __l2, __l3...); 726 : } 727 : } 728 : 729 : #if __cplusplus >= 201703L 730 : #define __cpp_lib_scoped_lock 201703L 731 : /** @brief A scoped lock type for multiple lockable objects. 732 : * 733 : * A scoped_lock controls mutex ownership within a scope, releasing 734 : * ownership in the destructor. 735 : * 736 : * @headerfile mutex 737 : * @since C++17 738 : */ 739 : template<typename... _MutexTypes> 740 : class scoped_lock 741 : { 742 : public: 743 : explicit scoped_lock(_MutexTypes&... __m) : _M_devices(std::tie(__m...)) 744 : { std::lock(__m...); } 745 : 746 : explicit scoped_lock(adopt_lock_t, _MutexTypes&... __m) noexcept 747 : : _M_devices(std::tie(__m...)) 748 : { } // calling thread owns mutex 749 : 750 : ~scoped_lock() 751 : { std::apply([](auto&... __m) { (__m.unlock(), ...); }, _M_devices); } 752 : 753 : scoped_lock(const scoped_lock&) = delete; 754 : scoped_lock& operator=(const scoped_lock&) = delete; 755 : 756 : private: 757 : tuple<_MutexTypes&...> _M_devices; 758 : }; 759 : 760 : template<> 761 : class scoped_lock<> 762 : { 763 : public: 764 : explicit scoped_lock() = default; 765 : explicit scoped_lock(adopt_lock_t) noexcept { } 766 : ~scoped_lock() = default; 767 : 768 : scoped_lock(const scoped_lock&) = delete; 769 : scoped_lock& operator=(const scoped_lock&) = delete; 770 : }; 771 : 772 : template<typename _Mutex> 773 : class scoped_lock<_Mutex> 774 : { 775 : public: 776 : using mutex_type = _Mutex; 777 : 778 : explicit scoped_lock(mutex_type& __m) : _M_device(__m) 779 : { _M_device.lock(); } 780 : 781 : explicit scoped_lock(adopt_lock_t, mutex_type& __m) noexcept 782 : : _M_device(__m) 783 : { } // calling thread owns mutex 784 : 785 : ~scoped_lock() 786 : { _M_device.unlock(); } 787 : 788 : scoped_lock(const scoped_lock&) = delete; 789 : scoped_lock& operator=(const scoped_lock&) = delete; 790 : 791 : private: 792 : mutex_type& _M_device; 793 : }; 794 : #endif // C++17 795 : 796 : #ifdef _GLIBCXX_HAS_GTHREADS 797 : /// Flag type used by std::call_once 798 : struct once_flag 799 : { 800 : constexpr once_flag() noexcept = default; 801 : 802 : /// Deleted copy constructor 803 : once_flag(const once_flag&) = delete; 804 : /// Deleted assignment operator 805 : once_flag& operator=(const once_flag&) = delete; 806 : 807 : private: 808 : // For gthreads targets a pthread_once_t is used with pthread_once, but 809 : // for most targets this doesn't work correctly for exceptional executions. 810 : __gthread_once_t _M_once = __GTHREAD_ONCE_INIT; 811 : 812 : struct _Prepare_execution; 813 : 814 : template<typename _Callable, typename... _Args> 815 : friend void 816 : call_once(once_flag& __once, _Callable&& __f, _Args&&... __args); 817 : }; 818 : 819 : /// @cond undocumented 820 : # ifdef _GLIBCXX_HAVE_TLS 821 : // If TLS is available use thread-local state for the type-erased callable 822 : // that is being run by std::call_once in the current thread. 823 : extern __thread void* __once_callable; 824 : extern __thread void (*__once_call)(); 825 : 826 : // RAII type to set up state for pthread_once call. 827 : struct once_flag::_Prepare_execution 828 : { 829 : template<typename _Callable> 830 : explicit 831 : _Prepare_execution(_Callable& __c) 832 : { 833 : // Store address in thread-local pointer: 834 : __once_callable = std::__addressof(__c); 835 : // Trampoline function to invoke the closure via thread-local pointer: 836 : __once_call = [] { (*static_cast<_Callable*>(__once_callable))(); }; 837 : } 838 : 839 : ~_Prepare_execution() 840 : { 841 : // PR libstdc++/82481 842 : __once_callable = nullptr; 843 : __once_call = nullptr; 844 : } 845 : 846 : _Prepare_execution(const _Prepare_execution&) = delete; 847 : _Prepare_execution& operator=(const _Prepare_execution&) = delete; 848 : }; 849 : 850 : # else 851 : // Without TLS use a global std::mutex and store the callable in a 852 : // global std::function. 853 : extern function<void()> __once_functor; 854 : 855 : extern void 856 : __set_once_functor_lock_ptr(unique_lock<mutex>*); 857 : 858 : extern mutex& 859 : __get_once_mutex(); 860 : 861 : // RAII type to set up state for pthread_once call. 862 : struct once_flag::_Prepare_execution 863 : { 864 : template<typename _Callable> 865 : explicit 866 : _Prepare_execution(_Callable& __c) 867 : { 868 : // Store the callable in the global std::function 869 : __once_functor = __c; 870 : __set_once_functor_lock_ptr(&_M_functor_lock); 871 : } 872 : 873 : ~_Prepare_execution() 874 : { 875 : if (_M_functor_lock) 876 : __set_once_functor_lock_ptr(nullptr); 877 : } 878 : 879 : private: 880 : // XXX This deadlocks if used recursively (PR 97949) 881 : unique_lock<mutex> _M_functor_lock{__get_once_mutex()}; 882 : 883 : _Prepare_execution(const _Prepare_execution&) = delete; 884 : _Prepare_execution& operator=(const _Prepare_execution&) = delete; 885 : }; 886 : # endif 887 : /// @endcond 888 : 889 : // This function is passed to pthread_once by std::call_once. 890 : // It runs __once_call() or __once_functor(). 891 : extern "C" void __once_proxy(void); 892 : 893 : /// Invoke a callable and synchronize with other calls using the same flag 894 : template<typename _Callable, typename... _Args> 895 : void 896 : call_once(once_flag& __once, _Callable&& __f, _Args&&... __args) 897 : { 898 : // Closure type that runs the function 899 : auto __callable = [&] { 900 : std::__invoke(std::forward<_Callable>(__f), 901 : std::forward<_Args>(__args)...); 902 : }; 903 : 904 : once_flag::_Prepare_execution __exec(__callable); 905 : 906 : // XXX pthread_once does not reset the flag if an exception is thrown. 907 : if (int __e = __gthread_once(&__once._M_once, &__once_proxy)) 908 : __throw_system_error(__e); 909 : } 910 : 911 : #else // _GLIBCXX_HAS_GTHREADS 912 : 913 : /// Flag type used by std::call_once 914 : struct once_flag 915 : { 916 : constexpr once_flag() noexcept = default; 917 : 918 : /// Deleted copy constructor 919 : once_flag(const once_flag&) = delete; 920 : /// Deleted assignment operator 921 : once_flag& operator=(const once_flag&) = delete; 922 : 923 : private: 924 : // There are two different std::once_flag interfaces, abstracting four 925 : // different implementations. 926 : // The single-threaded interface uses the _M_activate() and _M_finish(bool) 927 : // functions, which start and finish an active execution respectively. 928 : // See [thread.once.callonce] in C++11 for the definition of 929 : // active/passive/returning/exceptional executions. 930 : enum _Bits : int { _Init = 0, _Active = 1, _Done = 2 }; 931 : 932 : int _M_once = _Bits::_Init; 933 : 934 : // Check to see if all executions will be passive now. 935 : bool 936 : _M_passive() const noexcept; 937 : 938 : // Attempts to begin an active execution. 939 : bool _M_activate(); 940 : 941 : // Must be called to complete an active execution. 942 : // The argument is true if the active execution was a returning execution, 943 : // false if it was an exceptional execution. 944 : void _M_finish(bool __returning) noexcept; 945 : 946 : // RAII helper to call _M_finish. 947 : struct _Active_execution 948 : { 949 : explicit _Active_execution(once_flag& __flag) : _M_flag(__flag) { } 950 : 951 : ~_Active_execution() { _M_flag._M_finish(_M_returning); } 952 : 953 : _Active_execution(const _Active_execution&) = delete; 954 : _Active_execution& operator=(const _Active_execution&) = delete; 955 : 956 : once_flag& _M_flag; 957 : bool _M_returning = false; 958 : }; 959 : 960 : template<typename _Callable, typename... _Args> 961 : friend void 962 : call_once(once_flag& __once, _Callable&& __f, _Args&&... __args); 963 : }; 964 : 965 : // Inline definitions of std::once_flag members for single-threaded targets. 966 : 967 : inline bool 968 : once_flag::_M_passive() const noexcept 969 : { return _M_once == _Bits::_Done; } 970 : 971 : inline bool 972 : once_flag::_M_activate() 973 : { 974 : if (_M_once == _Bits::_Init) [[__likely__]] 975 : { 976 : _M_once = _Bits::_Active; 977 : return true; 978 : } 979 : else if (_M_passive()) // Caller should have checked this already. 980 : return false; 981 : else 982 : __throw_system_error(EDEADLK); 983 : } 984 : 985 : inline void 986 : once_flag::_M_finish(bool __returning) noexcept 987 : { _M_once = __returning ? _Bits::_Done : _Bits::_Init; } 988 : 989 : /// Invoke a callable and synchronize with other calls using the same flag 990 : template<typename _Callable, typename... _Args> 991 : inline void 992 : call_once(once_flag& __once, _Callable&& __f, _Args&&... __args) 993 : { 994 : if (__once._M_passive()) 995 : return; 996 : else if (__once._M_activate()) 997 : { 998 : once_flag::_Active_execution __exec(__once); 999 : 1000 : // _GLIBCXX_RESOLVE_LIB_DEFECTS 1001 : // 2442. call_once() shouldn't DECAY_COPY() 1002 : std::__invoke(std::forward<_Callable>(__f), 1003 : std::forward<_Args>(__args)...); 1004 : 1005 : // __f(__args...) did not throw 1006 : __exec._M_returning = true; 1007 : } 1008 : } 1009 : #endif // _GLIBCXX_HAS_GTHREADS 1010 : 1011 : /// @} group mutexes 1012 : _GLIBCXX_END_NAMESPACE_VERSION 1013 : } // namespace 1014 : 1015 : #endif // C++11 1016 : 1017 : #endif // _GLIBCXX_MUTEX |
![]() |
Generated by: LCOV version 2.0-1 |
</html>