1 #ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP 2 #define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP 3 4 // (C) Copyright 2006-8 Anthony Williams 5 // (C) Copyright 2011-2012,2017-2018 Vicente J. Botet Escriba 6 // 7 // Distributed under the Boost Software License, Version 1.0. (See 8 // accompanying file LICENSE_1_0.txt or copy at 9 // http://www.boost.org/LICENSE_1_0.txt) 10 11 #include <cstring> 12 #include <boost/assert.hpp> 13 #include <boost/detail/interlocked.hpp> 14 #include <boost/thread/win32/thread_primitives.hpp> 15 #include <boost/static_assert.hpp> 16 #include <limits.h> 17 #include <boost/thread/thread_time.hpp> 18 #ifdef BOOST_THREAD_USES_CHRONO 19 #include <boost/chrono/system_clocks.hpp> 20 #include <boost/chrono/ceil.hpp> 21 #endif 22 #include <boost/thread/detail/delete.hpp> 23 #include <boost/thread/detail/platform_time.hpp> 24 25 #include <boost/config/abi_prefix.hpp> 26 27 namespace boost 28 { 29 class shared_mutex 30 { 31 private: 32 struct state_data 33 { 34 unsigned long shared_count:11, 35 shared_waiting:11, 36 exclusive:1, 37 upgrade:1, 38 exclusive_waiting:7, 39 exclusive_waiting_blocked:1; 40 operator ==(state_data const & lhs,state_data const & rhs)41 friend bool operator==(state_data const& lhs,state_data const& rhs) 42 { 43 return std::memcmp(&lhs, &rhs, sizeof(lhs)) == 0; 44 } 45 }; 46 interlocked_compare_exchange(state_data * target,state_data new_value,state_data comparand)47 static state_data interlocked_compare_exchange(state_data* target, state_data new_value, state_data comparand) 48 { 49 BOOST_STATIC_ASSERT(sizeof(state_data) == sizeof(long)); 50 long new_val, comp; 51 std::memcpy(&new_val, &new_value, sizeof(new_value)); 52 std::memcpy(&comp, &comparand, sizeof(comparand)); 53 long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast<long*>(target), 54 new_val, 55 comp); 56 state_data result; 57 std::memcpy(&result, &res, sizeof(result)); 58 return result; 59 } 60 61 enum 62 { 63 unlock_sem = 0, 64 exclusive_sem = 1 65 }; 66 67 state_data state; 68 detail::win32::handle semaphores[2]; 69 detail::win32::handle upgrade_sem; 70 release_waiters(state_data old_state)71 void release_waiters(state_data old_state) 72 { 73 if(old_state.exclusive_waiting) 74 { 75 BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0); 76 } 77 78 if(old_state.shared_waiting || old_state.exclusive_waiting) 79 { 80 BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0); 81 } 82 } release_shared_waiters(state_data old_state)83 void release_shared_waiters(state_data old_state) 84 { 85 if(old_state.shared_waiting || old_state.exclusive_waiting) 86 { 87 BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0); 88 } 89 } 90 91 public: 92 BOOST_THREAD_NO_COPYABLE(shared_mutex) shared_mutex()93 shared_mutex() 94 { 95 semaphores[unlock_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX); 96 semaphores[exclusive_sem]=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX); 97 if (!semaphores[exclusive_sem]) 98 { 99 detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX); 100 boost::throw_exception(thread_resource_error()); 101 } 102 upgrade_sem=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX); 103 if (!upgrade_sem) 104 { 105 detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX); 106 detail::win32::release_semaphore(semaphores[exclusive_sem],LONG_MAX); 107 boost::throw_exception(thread_resource_error()); 108 } 109 state_data state_={0,0,0,0,0,0}; 110 state=state_; 111 } 112 ~shared_mutex()113 ~shared_mutex() 114 { 115 winapi::CloseHandle(upgrade_sem); 116 winapi::CloseHandle(semaphores[unlock_sem]); 117 winapi::CloseHandle(semaphores[exclusive_sem]); 118 } 119 try_lock_shared()120 bool try_lock_shared() 121 { 122 state_data old_state=state; 123 for(;;) 124 { 125 state_data new_state=old_state; 126 if(!new_state.exclusive && !new_state.exclusive_waiting_blocked) 127 { 128 ++new_state.shared_count; 129 if(!new_state.shared_count) 130 { 131 return false; 132 } 133 } 134 135 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 136 if(current_state==old_state) 137 { 138 break; 139 } 140 old_state=current_state; 141 } 142 return !(old_state.exclusive| old_state.exclusive_waiting_blocked); 143 } 144 lock_shared()145 void lock_shared() 146 { 147 for(;;) 148 { 149 state_data old_state=state; 150 for(;;) 151 { 152 state_data new_state=old_state; 153 if(new_state.exclusive || new_state.exclusive_waiting_blocked) 154 { 155 ++new_state.shared_waiting; 156 if(!new_state.shared_waiting) 157 { 158 boost::throw_exception(boost::lock_error()); 159 } 160 } 161 else 162 { 163 ++new_state.shared_count; 164 if(!new_state.shared_count) 165 { 166 boost::throw_exception(boost::lock_error()); 167 } 168 } 169 170 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 171 if(current_state==old_state) 172 { 173 break; 174 } 175 old_state=current_state; 176 } 177 178 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) 179 { 180 return; 181 } 182 183 BOOST_VERIFY(winapi::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::win32::infinite,0)==0); 184 } 185 } 186 187 private: getMs(detail::platform_duration const & d)188 unsigned long getMs(detail::platform_duration const& d) 189 { 190 return static_cast<unsigned long>(d.getMs()); 191 } 192 193 template <typename Duration> getMs(Duration const & d)194 unsigned long getMs(Duration const& d) 195 { 196 return static_cast<unsigned long>(chrono::ceil<chrono::milliseconds>(d).count()); 197 } 198 199 template <typename Clock, typename Timepoint, typename Duration> do_lock_shared_until(Timepoint const & t,Duration const & max)200 bool do_lock_shared_until(Timepoint const& t, Duration const& max) 201 { 202 for(;;) 203 { 204 state_data old_state=state; 205 for(;;) 206 { 207 state_data new_state=old_state; 208 if(new_state.exclusive || new_state.exclusive_waiting_blocked) 209 { 210 ++new_state.shared_waiting; 211 if(!new_state.shared_waiting) 212 { 213 boost::throw_exception(boost::lock_error()); 214 } 215 } 216 else 217 { 218 ++new_state.shared_count; 219 if(!new_state.shared_count) 220 { 221 boost::throw_exception(boost::lock_error()); 222 } 223 } 224 225 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 226 if(current_state==old_state) 227 { 228 break; 229 } 230 old_state=current_state; 231 } 232 233 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) 234 { 235 return true; 236 } 237 238 // If the clock is the system clock, it may jump while this function 239 // is waiting. To compensate for this and time out near the correct 240 // time, we call WaitForSingleObjectEx() in a loop with a short 241 // timeout and recheck the time remaining each time through the loop. 242 unsigned long res=0; 243 for(;;) 244 { 245 Duration d(t - Clock::now()); 246 if(d <= Duration::zero()) // timeout occurred 247 { 248 res=detail::win32::timeout; 249 break; 250 } 251 if(max != Duration::zero()) 252 { 253 d = (std::min)(d, max); 254 } 255 res=winapi::WaitForSingleObjectEx(semaphores[unlock_sem],getMs(d),0); 256 if(res!=detail::win32::timeout) // semaphore released 257 { 258 break; 259 } 260 } 261 262 if(res==detail::win32::timeout) 263 { 264 for(;;) 265 { 266 state_data new_state=old_state; 267 if(new_state.exclusive || new_state.exclusive_waiting_blocked) 268 { 269 if(new_state.shared_waiting) 270 { 271 --new_state.shared_waiting; 272 } 273 } 274 else 275 { 276 ++new_state.shared_count; 277 if(!new_state.shared_count) 278 { 279 return false; 280 } 281 } 282 283 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 284 if(current_state==old_state) 285 { 286 break; 287 } 288 old_state=current_state; 289 } 290 291 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) 292 { 293 return true; 294 } 295 return false; 296 } 297 298 BOOST_ASSERT(res==0); 299 } 300 } 301 public: 302 303 #if defined BOOST_THREAD_USES_DATETIME 304 template<typename TimeDuration> timed_lock_shared(TimeDuration const & relative_time)305 bool timed_lock_shared(TimeDuration const & relative_time) 306 { 307 const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(relative_time)); 308 // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) 309 return do_lock_shared_until<detail::mono_platform_clock>(t, detail::platform_duration::zero()); 310 } timed_lock_shared(boost::system_time const & wait_until)311 bool timed_lock_shared(boost::system_time const& wait_until) 312 { 313 const detail::real_platform_timepoint t(wait_until); 314 return do_lock_shared_until<detail::real_platform_clock>(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); 315 } 316 #endif 317 318 #ifdef BOOST_THREAD_USES_CHRONO 319 template <class Rep, class Period> try_lock_shared_for(const chrono::duration<Rep,Period> & rel_time)320 bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time) 321 { 322 const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time); 323 typedef typename chrono::duration<Rep, Period> Duration; 324 typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration; 325 // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) 326 return do_lock_shared_until<chrono::steady_clock>(t, common_duration::zero()); 327 } 328 template <class Duration> try_lock_shared_until(const chrono::time_point<chrono::steady_clock,Duration> & t)329 bool try_lock_shared_until(const chrono::time_point<chrono::steady_clock, Duration>& t) 330 { 331 typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration; 332 // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) 333 return do_lock_shared_until<chrono::steady_clock>(t, common_duration::zero()); 334 } 335 template <class Clock, class Duration> try_lock_shared_until(const chrono::time_point<Clock,Duration> & t)336 bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& t) 337 { 338 typedef typename common_type<Duration, typename Clock::duration>::type common_duration; 339 return do_lock_shared_until<Clock>(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); 340 } 341 #endif 342 unlock_shared()343 void unlock_shared() 344 { 345 state_data old_state=state; 346 for(;;) 347 { 348 state_data new_state=old_state; 349 bool const last_reader=!--new_state.shared_count; 350 351 if(last_reader) 352 { 353 if(new_state.upgrade) 354 { 355 new_state.upgrade=false; 356 new_state.exclusive=true; 357 } 358 else 359 { 360 if(new_state.exclusive_waiting) 361 { 362 --new_state.exclusive_waiting; 363 new_state.exclusive_waiting_blocked=false; 364 } 365 new_state.shared_waiting=0; 366 } 367 } 368 369 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 370 if(current_state==old_state) 371 { 372 if(last_reader) 373 { 374 if(old_state.upgrade) 375 { 376 BOOST_VERIFY(winapi::ReleaseSemaphore(upgrade_sem,1,0)!=0); 377 } 378 else 379 { 380 release_waiters(old_state); 381 } 382 } 383 break; 384 } 385 old_state=current_state; 386 } 387 } 388 try_lock()389 bool try_lock() 390 { 391 state_data old_state=state; 392 for(;;) 393 { 394 state_data new_state=old_state; 395 if(new_state.shared_count || new_state.exclusive) 396 { 397 return false; 398 } 399 else 400 { 401 new_state.exclusive=true; 402 } 403 404 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 405 if(current_state==old_state) 406 { 407 break; 408 } 409 old_state=current_state; 410 } 411 return true; 412 } 413 lock()414 void lock() 415 { 416 for(;;) 417 { 418 state_data old_state=state; 419 for(;;) 420 { 421 state_data new_state=old_state; 422 if(new_state.shared_count || new_state.exclusive) 423 { 424 ++new_state.exclusive_waiting; 425 if(!new_state.exclusive_waiting) 426 { 427 boost::throw_exception(boost::lock_error()); 428 } 429 430 new_state.exclusive_waiting_blocked=true; 431 } 432 else 433 { 434 new_state.exclusive=true; 435 } 436 437 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 438 if(current_state==old_state) 439 { 440 break; 441 } 442 old_state=current_state; 443 } 444 445 if(!old_state.shared_count && !old_state.exclusive) 446 { 447 return; 448 } 449 450 #ifndef UNDER_CE 451 const bool wait_all = true; 452 #else 453 const bool wait_all = false; 454 #endif 455 BOOST_VERIFY(winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::win32::infinite,0)<2); 456 } 457 } 458 459 private: 460 template <typename Clock, typename Timepoint, typename Duration> do_lock_until(Timepoint const & t,Duration const & max)461 bool do_lock_until(Timepoint const& t, Duration const& max) 462 { 463 for(;;) 464 { 465 state_data old_state=state; 466 for(;;) 467 { 468 state_data new_state=old_state; 469 if(new_state.shared_count || new_state.exclusive) 470 { 471 ++new_state.exclusive_waiting; 472 if(!new_state.exclusive_waiting) 473 { 474 boost::throw_exception(boost::lock_error()); 475 } 476 477 new_state.exclusive_waiting_blocked=true; 478 } 479 else 480 { 481 new_state.exclusive=true; 482 } 483 484 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 485 if(current_state==old_state) 486 { 487 break; 488 } 489 old_state=current_state; 490 } 491 492 if(!old_state.shared_count && !old_state.exclusive) 493 { 494 return true; 495 } 496 497 // If the clock is the system clock, it may jump while this function 498 // is waiting. To compensate for this and time out near the correct 499 // time, we call WaitForMultipleObjectsEx() in a loop with a short 500 // timeout and recheck the time remaining each time through the loop. 501 unsigned long wait_res=0; 502 for(;;) 503 { 504 Duration d(t - Clock::now()); 505 if(d <= Duration::zero()) // timeout occurred 506 { 507 wait_res=detail::win32::timeout; 508 break; 509 } 510 if(max != Duration::zero()) 511 { 512 d = (std::min)(d, max); 513 } 514 #ifndef UNDER_CE 515 wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,true,getMs(d),0); 516 #else 517 wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,false,getMs(d),0); 518 #endif 519 //wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,getMs(d), 0); 520 521 if(wait_res!=detail::win32::timeout) // semaphore released 522 { 523 break; 524 } 525 } 526 527 if(wait_res==detail::win32::timeout) 528 { 529 for(;;) 530 { 531 bool must_notify = false; 532 state_data new_state=old_state; 533 if(new_state.shared_count || new_state.exclusive) 534 { 535 if(new_state.exclusive_waiting) 536 { 537 if(!--new_state.exclusive_waiting) 538 { 539 new_state.exclusive_waiting_blocked=false; 540 must_notify = true; 541 } 542 } 543 } 544 else 545 { 546 new_state.exclusive=true; 547 } 548 549 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 550 if (must_notify) 551 { 552 BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0); 553 } 554 555 if(current_state==old_state) 556 { 557 break; 558 } 559 old_state=current_state; 560 } 561 if(!old_state.shared_count && !old_state.exclusive) 562 { 563 return true; 564 } 565 return false; 566 } 567 568 BOOST_ASSERT(wait_res<2); 569 } 570 } 571 public: 572 573 #if defined BOOST_THREAD_USES_DATETIME timed_lock(boost::system_time const & wait_until)574 bool timed_lock(boost::system_time const& wait_until) 575 { 576 const detail::real_platform_timepoint t(wait_until); 577 return do_lock_until<detail::real_platform_clock>(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); 578 } 579 template<typename TimeDuration> timed_lock(TimeDuration const & relative_time)580 bool timed_lock(TimeDuration const & relative_time) 581 { 582 const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(relative_time)); 583 // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) 584 return do_lock_until<detail::mono_platform_clock>(t, detail::platform_duration::zero()); 585 } 586 #endif 587 #ifdef BOOST_THREAD_USES_CHRONO 588 template <class Rep, class Period> try_lock_for(const chrono::duration<Rep,Period> & rel_time)589 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) 590 { 591 const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time); 592 typedef typename chrono::duration<Rep, Period> Duration; 593 typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration; 594 // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) 595 return do_lock_until<chrono::steady_clock>(t, common_duration::zero()); 596 } 597 template <class Duration> try_lock_until(const chrono::time_point<chrono::steady_clock,Duration> & t)598 bool try_lock_until(const chrono::time_point<chrono::steady_clock, Duration>& t) 599 { 600 typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration; 601 // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) 602 return do_lock_until<chrono::steady_clock>(t, common_duration::zero()); 603 } 604 template <class Clock, class Duration> try_lock_until(const chrono::time_point<Clock,Duration> & t)605 bool try_lock_until(const chrono::time_point<Clock, Duration>& t) 606 { 607 typedef typename common_type<Duration, typename Clock::duration>::type common_duration; 608 return do_lock_until<Clock>(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); 609 } 610 #endif 611 unlock()612 void unlock() 613 { 614 state_data old_state=state; 615 for(;;) 616 { 617 state_data new_state=old_state; 618 new_state.exclusive=false; 619 if(new_state.exclusive_waiting) 620 { 621 --new_state.exclusive_waiting; 622 new_state.exclusive_waiting_blocked=false; 623 } 624 new_state.shared_waiting=0; 625 626 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 627 if(current_state==old_state) 628 { 629 break; 630 } 631 old_state=current_state; 632 } 633 release_waiters(old_state); 634 } 635 lock_upgrade()636 void lock_upgrade() 637 { 638 for(;;) 639 { 640 state_data old_state=state; 641 for(;;) 642 { 643 state_data new_state=old_state; 644 if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade) 645 { 646 ++new_state.shared_waiting; 647 if(!new_state.shared_waiting) 648 { 649 boost::throw_exception(boost::lock_error()); 650 } 651 } 652 else 653 { 654 ++new_state.shared_count; 655 if(!new_state.shared_count) 656 { 657 boost::throw_exception(boost::lock_error()); 658 } 659 new_state.upgrade=true; 660 } 661 662 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 663 if(current_state==old_state) 664 { 665 break; 666 } 667 old_state=current_state; 668 } 669 670 if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade)) 671 { 672 return; 673 } 674 675 BOOST_VERIFY(winapi::WaitForSingleObjectEx(semaphores[unlock_sem],winapi::infinite,0)==0); 676 } 677 } 678 try_lock_upgrade()679 bool try_lock_upgrade() 680 { 681 state_data old_state=state; 682 for(;;) 683 { 684 state_data new_state=old_state; 685 if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade) 686 { 687 return false; 688 } 689 else 690 { 691 ++new_state.shared_count; 692 if(!new_state.shared_count) 693 { 694 return false; 695 } 696 new_state.upgrade=true; 697 } 698 699 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 700 if(current_state==old_state) 701 { 702 break; 703 } 704 old_state=current_state; 705 } 706 return true; 707 } 708 unlock_upgrade()709 void unlock_upgrade() 710 { 711 state_data old_state=state; 712 for(;;) 713 { 714 state_data new_state=old_state; 715 new_state.upgrade=false; 716 bool const last_reader=!--new_state.shared_count; 717 718 new_state.shared_waiting=0; 719 if(last_reader) 720 { 721 if(new_state.exclusive_waiting) 722 { 723 --new_state.exclusive_waiting; 724 new_state.exclusive_waiting_blocked=false; 725 } 726 } 727 728 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 729 if(current_state==old_state) 730 { 731 if(last_reader) 732 { 733 release_waiters(old_state); 734 } 735 else { 736 release_shared_waiters(old_state); 737 } 738 // #7720 739 //else { 740 // release_waiters(old_state); 741 //} 742 break; 743 } 744 old_state=current_state; 745 } 746 } 747 unlock_upgrade_and_lock()748 void unlock_upgrade_and_lock() 749 { 750 state_data old_state=state; 751 for(;;) 752 { 753 state_data new_state=old_state; 754 bool const last_reader=!--new_state.shared_count; 755 756 if(last_reader) 757 { 758 new_state.upgrade=false; 759 new_state.exclusive=true; 760 } 761 762 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 763 if(current_state==old_state) 764 { 765 if(!last_reader) 766 { 767 BOOST_VERIFY(winapi::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite,0)==0); 768 } 769 break; 770 } 771 old_state=current_state; 772 } 773 } 774 unlock_and_lock_upgrade()775 void unlock_and_lock_upgrade() 776 { 777 state_data old_state=state; 778 for(;;) 779 { 780 state_data new_state=old_state; 781 new_state.exclusive=false; 782 new_state.upgrade=true; 783 ++new_state.shared_count; 784 if(new_state.exclusive_waiting) 785 { 786 --new_state.exclusive_waiting; 787 new_state.exclusive_waiting_blocked=false; 788 } 789 new_state.shared_waiting=0; 790 791 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 792 if(current_state==old_state) 793 { 794 break; 795 } 796 old_state=current_state; 797 } 798 release_waiters(old_state); 799 } 800 unlock_and_lock_shared()801 void unlock_and_lock_shared() 802 { 803 state_data old_state=state; 804 for(;;) 805 { 806 state_data new_state=old_state; 807 new_state.exclusive=false; 808 ++new_state.shared_count; 809 if(new_state.exclusive_waiting) 810 { 811 --new_state.exclusive_waiting; 812 new_state.exclusive_waiting_blocked=false; 813 } 814 new_state.shared_waiting=0; 815 816 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 817 if(current_state==old_state) 818 { 819 break; 820 } 821 old_state=current_state; 822 } 823 release_waiters(old_state); 824 } unlock_upgrade_and_lock_shared()825 void unlock_upgrade_and_lock_shared() 826 { 827 state_data old_state=state; 828 for(;;) 829 { 830 state_data new_state=old_state; 831 new_state.upgrade=false; 832 if(new_state.exclusive_waiting) 833 { 834 --new_state.exclusive_waiting; 835 new_state.exclusive_waiting_blocked=false; 836 } 837 new_state.shared_waiting=0; 838 839 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 840 if(current_state==old_state) 841 { 842 break; 843 } 844 old_state=current_state; 845 } 846 release_waiters(old_state); 847 } 848 849 }; 850 typedef shared_mutex upgrade_mutex; 851 852 } 853 854 #include <boost/config/abi_suffix.hpp> 855 856 #endif 857