1 #ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP 2 #define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP 3 4 // (C) Copyright 2006-8 Anthony Williams 5 // (C) Copyright 2012 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 <boost/assert.hpp> 12 #include <boost/static_assert.hpp> 13 #include <boost/thread/mutex.hpp> 14 #include <boost/thread/condition_variable.hpp> 15 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 16 #include <boost/thread/detail/thread_interruption.hpp> 17 #endif 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/assert.hpp> 24 25 #include <boost/config/abi_prefix.hpp> 26 27 namespace boost 28 { 29 class shared_mutex 30 { 31 private: 32 class state_data 33 { 34 public: state_data()35 state_data () : 36 shared_count(0), 37 exclusive(false), 38 upgrade(false), 39 exclusive_waiting_blocked(false) 40 {} 41 assert_free() const42 void assert_free() const 43 { 44 BOOST_ASSERT( ! exclusive ); 45 BOOST_ASSERT( ! upgrade ); 46 BOOST_ASSERT( shared_count==0 ); 47 } 48 assert_locked() const49 void assert_locked() const 50 { 51 BOOST_ASSERT( exclusive ); 52 BOOST_ASSERT( shared_count==0 ); 53 BOOST_ASSERT( ! upgrade ); 54 } 55 assert_lock_shared() const56 void assert_lock_shared () const 57 { 58 BOOST_ASSERT( ! exclusive ); 59 BOOST_ASSERT( shared_count>0 ); 60 //BOOST_ASSERT( (! upgrade) || (shared_count>1)); 61 // if upgraded there are at least 2 threads sharing the mutex, 62 // except when unlock_upgrade_and_lock has decreased the number of readers but has not taken yet exclusive ownership. 63 } 64 assert_lock_upgraded() const65 void assert_lock_upgraded () const 66 { 67 BOOST_ASSERT( ! exclusive ); 68 BOOST_ASSERT( upgrade ); 69 BOOST_ASSERT( shared_count>0 ); 70 } 71 assert_lock_not_upgraded() const72 void assert_lock_not_upgraded () const 73 { 74 BOOST_ASSERT( ! upgrade ); 75 } 76 can_lock() const77 bool can_lock () const 78 { 79 return ! (shared_count || exclusive); 80 } 81 exclusive_blocked(bool blocked)82 void exclusive_blocked (bool blocked) 83 { 84 exclusive_waiting_blocked = blocked; 85 } 86 lock()87 void lock () 88 { 89 exclusive = true; 90 } 91 unlock()92 void unlock () 93 { 94 exclusive = false; 95 exclusive_waiting_blocked = false; 96 } 97 can_lock_shared() const98 bool can_lock_shared () const 99 { 100 return ! (exclusive || exclusive_waiting_blocked); 101 } 102 is_last_shared() const103 bool is_last_shared () const 104 { 105 return !shared_count ; 106 } get_shared_count() const107 unsigned get_shared_count () const 108 { 109 return shared_count ; 110 } lock_shared()111 unsigned lock_shared () 112 { 113 return ++shared_count; 114 } 115 116 unlock_shared()117 void unlock_shared () 118 { 119 --shared_count; 120 } 121 unlock_shared_downgrades()122 bool unlock_shared_downgrades() 123 { 124 if (upgrade) { 125 upgrade=false; 126 exclusive=true; 127 return true; 128 } else { 129 exclusive_waiting_blocked=false; 130 return false; 131 } 132 } 133 lock_upgrade()134 void lock_upgrade () 135 { 136 lock_shared (); 137 upgrade=true; 138 } can_lock_upgrade() const139 bool can_lock_upgrade () const 140 { 141 return ! (exclusive || exclusive_waiting_blocked || upgrade); 142 } 143 unlock_upgrade()144 void unlock_upgrade () 145 { 146 upgrade=false; 147 unlock_shared(); 148 } 149 150 //private: 151 unsigned shared_count; 152 bool exclusive; 153 bool upgrade; 154 bool exclusive_waiting_blocked; 155 }; 156 157 158 159 state_data state; 160 boost::mutex state_change; 161 boost::condition_variable shared_cond; 162 boost::condition_variable exclusive_cond; 163 boost::condition_variable upgrade_cond; 164 release_waiters()165 void release_waiters() 166 { 167 exclusive_cond.notify_one(); 168 shared_cond.notify_all(); 169 } 170 171 public: 172 BOOST_THREAD_NO_COPYABLE(shared_mutex) 173 shared_mutex()174 shared_mutex() 175 { 176 } 177 ~shared_mutex()178 ~shared_mutex() 179 { 180 } 181 lock_shared()182 void lock_shared() 183 { 184 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 185 boost::this_thread::disable_interruption do_not_disturb; 186 #endif 187 boost::unique_lock<boost::mutex> lk(state_change); 188 189 while(!state.can_lock_shared()) 190 { 191 shared_cond.wait(lk); 192 } 193 state.lock_shared(); 194 } 195 try_lock_shared()196 bool try_lock_shared() 197 { 198 boost::unique_lock<boost::mutex> lk(state_change); 199 if(!state.can_lock_shared()) 200 { 201 return false; 202 } 203 else 204 { 205 state.lock_shared(); 206 return true; 207 } 208 } 209 210 #if defined BOOST_THREAD_USES_DATETIME timed_lock_shared(system_time const & timeout)211 bool timed_lock_shared(system_time const& timeout) 212 { 213 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 214 boost::this_thread::disable_interruption do_not_disturb; 215 #endif 216 boost::unique_lock<boost::mutex> lk(state_change); 217 218 while(!state.can_lock_shared()) 219 { 220 if(!shared_cond.timed_wait(lk,timeout)) 221 { 222 return false; 223 } 224 } 225 state.lock_shared(); 226 return true; 227 } 228 229 template<typename TimeDuration> timed_lock_shared(TimeDuration const & relative_time)230 bool timed_lock_shared(TimeDuration const & relative_time) 231 { 232 return timed_lock_shared(get_system_time()+relative_time); 233 } 234 #endif 235 #ifdef BOOST_THREAD_USES_CHRONO 236 template <class Rep, class Period> try_lock_shared_for(const chrono::duration<Rep,Period> & rel_time)237 bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time) 238 { 239 return try_lock_shared_until(chrono::steady_clock::now() + rel_time); 240 } 241 template <class Clock, class Duration> try_lock_shared_until(const chrono::time_point<Clock,Duration> & abs_time)242 bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time) 243 { 244 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 245 boost::this_thread::disable_interruption do_not_disturb; 246 #endif 247 boost::unique_lock<boost::mutex> lk(state_change); 248 249 while(!state.can_lock_shared()) 250 { 251 if(cv_status::timeout==shared_cond.wait_until(lk,abs_time)) 252 { 253 return false; 254 } 255 } 256 state.lock_shared(); 257 return true; 258 } 259 #endif unlock_shared()260 void unlock_shared() 261 { 262 boost::unique_lock<boost::mutex> lk(state_change); 263 state.assert_lock_shared(); 264 state.unlock_shared(); 265 if (state.get_shared_count () == 0) 266 { 267 if (state.unlock_shared_downgrades()) 268 { 269 lk.unlock(); 270 upgrade_cond.notify_one(); 271 } else { 272 lk.unlock(); 273 } 274 release_waiters(); 275 } 276 } 277 lock()278 void lock() 279 { 280 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 281 boost::this_thread::disable_interruption do_not_disturb; 282 #endif 283 boost::unique_lock<boost::mutex> lk(state_change); 284 285 while(!state.can_lock()) 286 { 287 state.exclusive_blocked(true); 288 exclusive_cond.wait(lk); 289 } 290 state.lock(); 291 } 292 293 #if defined BOOST_THREAD_USES_DATETIME timed_lock(system_time const & timeout)294 bool timed_lock(system_time const& timeout) 295 { 296 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 297 boost::this_thread::disable_interruption do_not_disturb; 298 #endif 299 boost::unique_lock<boost::mutex> lk(state_change); 300 301 while(!state.can_lock()) 302 { 303 state.exclusive_blocked(true); 304 if(!exclusive_cond.timed_wait(lk,timeout)) 305 { 306 if(!state.can_lock()) 307 { 308 state.exclusive_blocked(false); 309 release_waiters(); 310 return false; 311 } 312 break; 313 } 314 } 315 state.exclusive=true; 316 //state.lock(); 317 return true; 318 } 319 320 template<typename TimeDuration> timed_lock(TimeDuration const & relative_time)321 bool timed_lock(TimeDuration const & relative_time) 322 { 323 return timed_lock(get_system_time()+relative_time); 324 } 325 #endif 326 #ifdef BOOST_THREAD_USES_CHRONO 327 template <class Rep, class Period> try_lock_for(const chrono::duration<Rep,Period> & rel_time)328 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) 329 { 330 return try_lock_until(chrono::steady_clock::now() + rel_time); 331 } 332 template <class Clock, class Duration> try_lock_until(const chrono::time_point<Clock,Duration> & abs_time)333 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time) 334 { 335 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 336 boost::this_thread::disable_interruption do_not_disturb; 337 #endif 338 boost::unique_lock<boost::mutex> lk(state_change); 339 340 while(!state.can_lock()) 341 { 342 state.exclusive_blocked(true); 343 if(cv_status::timeout == exclusive_cond.wait_until(lk,abs_time)) 344 { 345 if(!state.can_lock()) 346 { 347 state.exclusive_blocked(false); 348 release_waiters(); 349 return false; 350 } 351 break; 352 } 353 } 354 state.exclusive=true; 355 //state.lock(); 356 return true; 357 } 358 #endif 359 try_lock()360 bool try_lock() 361 { 362 boost::unique_lock<boost::mutex> lk(state_change); 363 364 if(!state.can_lock()) 365 { 366 return false; 367 } 368 else 369 { 370 state.lock(); 371 return true; 372 } 373 374 } 375 unlock()376 void unlock() 377 { 378 boost::unique_lock<boost::mutex> lk(state_change); 379 state.assert_locked(); 380 state.unlock(); 381 state.assert_free(); 382 release_waiters(); 383 } 384 lock_upgrade()385 void lock_upgrade() 386 { 387 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 388 boost::this_thread::disable_interruption do_not_disturb; 389 #endif 390 boost::unique_lock<boost::mutex> lk(state_change); 391 while(!state.can_lock_upgrade()) 392 { 393 shared_cond.wait(lk); 394 } 395 state.lock_upgrade(); 396 } 397 398 #if defined BOOST_THREAD_USES_DATETIME timed_lock_upgrade(system_time const & timeout)399 bool timed_lock_upgrade(system_time const& timeout) 400 { 401 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 402 boost::this_thread::disable_interruption do_not_disturb; 403 #endif 404 boost::unique_lock<boost::mutex> lk(state_change); 405 while(!state.can_lock_upgrade()) 406 { 407 if(!shared_cond.timed_wait(lk,timeout)) 408 { 409 if(!state.can_lock_upgrade()) 410 { 411 return false; 412 } 413 break; 414 } 415 } 416 state.lock_upgrade(); 417 return true; 418 } 419 420 template<typename TimeDuration> timed_lock_upgrade(TimeDuration const & relative_time)421 bool timed_lock_upgrade(TimeDuration const & relative_time) 422 { 423 return timed_lock_upgrade(get_system_time()+relative_time); 424 } 425 #endif 426 #ifdef BOOST_THREAD_USES_CHRONO 427 template <class Rep, class Period> try_lock_upgrade_for(const chrono::duration<Rep,Period> & rel_time)428 bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time) 429 { 430 return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time); 431 } 432 template <class Clock, class Duration> try_lock_upgrade_until(const chrono::time_point<Clock,Duration> & abs_time)433 bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time) 434 { 435 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 436 boost::this_thread::disable_interruption do_not_disturb; 437 #endif 438 boost::unique_lock<boost::mutex> lk(state_change); 439 while(!state.can_lock_upgrade()) 440 { 441 if(cv_status::timeout == shared_cond.wait_until(lk,abs_time)) 442 { 443 if(!state.can_lock_upgrade()) 444 { 445 return false; 446 } 447 break; 448 } 449 } 450 state.lock_upgrade(); 451 return true; 452 } 453 #endif try_lock_upgrade()454 bool try_lock_upgrade() 455 { 456 boost::unique_lock<boost::mutex> lk(state_change); 457 if(!state.can_lock_upgrade()) 458 { 459 return false; 460 } 461 else 462 { 463 state.lock_upgrade(); 464 state.assert_lock_upgraded(); 465 return true; 466 } 467 } 468 unlock_upgrade()469 void unlock_upgrade() 470 { 471 boost::unique_lock<boost::mutex> lk(state_change); 472 state.assert_lock_upgraded(); 473 state.unlock_upgrade(); 474 state.assert_lock_not_upgraded (); 475 if(state.get_shared_count () == 0) 476 { 477 state.exclusive_blocked(false); 478 lk.unlock(); 479 release_waiters(); 480 } else { 481 lk.unlock(); 482 shared_cond.notify_all(); 483 } 484 } 485 486 // Upgrade <-> Exclusive unlock_upgrade_and_lock()487 void unlock_upgrade_and_lock() 488 { 489 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 490 boost::this_thread::disable_interruption do_not_disturb; 491 #endif 492 boost::unique_lock<boost::mutex> lk(state_change); 493 state.assert_lock_upgraded(); 494 // assert state.get_shared_count() >=1 495 while( 496 //! state.exclusive_waiting_blocked // Fixme: is this needed? 497 //&& 498 state.get_shared_count()!=1) 499 { 500 upgrade_cond.wait(lk); 501 } 502 state.unlock_upgrade(); 503 state.lock(); 504 state.assert_locked(); 505 } 506 unlock_and_lock_upgrade()507 void unlock_and_lock_upgrade() 508 { 509 boost::unique_lock<boost::mutex> lk(state_change); 510 state.assert_locked(); 511 state.unlock(); 512 state.lock_upgrade(); 513 state.assert_lock_upgraded(); 514 release_waiters(); 515 } 516 try_unlock_upgrade_and_lock()517 bool try_unlock_upgrade_and_lock() 518 { 519 boost::unique_lock<boost::mutex> lk(state_change); 520 state.assert_lock_upgraded(); 521 if( //!state.exclusive // this should be removed once the assertion work 522 ! state.exclusive_waiting_blocked // Fixme: why this is needed? 523 //&& state.upgrade // this should be removed once the assertion work 524 && state.get_shared_count()==1) 525 { 526 state.unlock_upgrade(); 527 state.lock(); 528 state.assert_locked(); 529 return true; 530 } 531 return false; 532 } 533 #ifdef BOOST_THREAD_USES_CHRONO 534 template <class Rep, class Period> 535 bool try_unlock_upgrade_and_lock_for(const chrono::duration<Rep,Period> & rel_time)536 try_unlock_upgrade_and_lock_for( 537 const chrono::duration<Rep, Period>& rel_time) 538 { 539 return try_unlock_upgrade_and_lock_until( 540 chrono::steady_clock::now() + rel_time); 541 } 542 template <class Clock, class Duration> 543 bool try_unlock_upgrade_and_lock_until(const chrono::time_point<Clock,Duration> & abs_time)544 try_unlock_upgrade_and_lock_until( 545 const chrono::time_point<Clock, Duration>& abs_time) 546 { 547 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 548 boost::this_thread::disable_interruption do_not_disturb; 549 #endif 550 boost::unique_lock<boost::mutex> lk(state_change); 551 state.assert_lock_upgraded(); 552 if (//state.exclusive // this should be removed once the assertion work 553 state.exclusive_waiting_blocked // Fixme: is this needed? 554 //|| ! state.upgrade // this should be removed once the assertion work 555 || state.get_shared_count() != 1) 556 { 557 for (;;) 558 { 559 //cv_status status = shared_cond.wait_until(lk,abs_time); 560 cv_status status = upgrade_cond.wait_until(lk,abs_time); 561 if (//!state.exclusive // this should be removed once the assertion work 562 ! state.exclusive_waiting_blocked // Fixme: is this needed? 563 //&& ! state.upgrade // this should be removed once the assertion work 564 && state.get_shared_count() == 1) 565 break; 566 if(status == cv_status::timeout) 567 return false; 568 } 569 } 570 state.unlock_upgrade(); 571 state.lock(); 572 return true; 573 } 574 #endif 575 576 // Shared <-> Exclusive unlock_and_lock_shared()577 void unlock_and_lock_shared() 578 { 579 boost::unique_lock<boost::mutex> lk(state_change); 580 state.assert_locked(); 581 state.unlock(); 582 state.lock_shared(); 583 release_waiters(); 584 } 585 586 #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS try_unlock_shared_and_lock()587 bool try_unlock_shared_and_lock() 588 { 589 boost::unique_lock<boost::mutex> lk(state_change); 590 state.assert_lock_shared(); 591 if( //!state.exclusive // this should be removed once the assertion work 592 ! state.exclusive_waiting_blocked // Fixme: why this is needed? 593 //&& ! state.upgrade // Fixme: why this is needed if state.get_shared_count()==1? 594 && state.get_shared_count()==1) 595 { 596 state.unlock_shared(); 597 state.lock(); 598 return true; 599 } 600 return false; 601 } 602 #ifdef BOOST_THREAD_USES_CHRONO 603 template <class Rep, class Period> 604 bool try_unlock_shared_and_lock_for(const chrono::duration<Rep,Period> & rel_time)605 try_unlock_shared_and_lock_for( 606 const chrono::duration<Rep, Period>& rel_time) 607 { 608 return try_unlock_shared_and_lock_until( 609 chrono::steady_clock::now() + rel_time); 610 } 611 template <class Clock, class Duration> 612 bool try_unlock_shared_and_lock_until(const chrono::time_point<Clock,Duration> & abs_time)613 try_unlock_shared_and_lock_until( 614 const chrono::time_point<Clock, Duration>& abs_time) 615 { 616 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 617 boost::this_thread::disable_interruption do_not_disturb; 618 #endif 619 boost::unique_lock<boost::mutex> lk(state_change); 620 state.assert_lock_shared(); 621 if ( // !state.exclusive // this should be removed once the assertion work 622 state.exclusive_waiting_blocked // Fixme: is this needed? 623 //|| state.upgrade // Fixme: why this is needed if state.get_shared_count()==1? 624 || state.get_shared_count() != 1) 625 { 626 for (;;) 627 { 628 cv_status status = shared_cond.wait_until(lk,abs_time); 629 if ( //! state.exclusive // this should be removed once the assertion work 630 ! state.exclusive_waiting_blocked // Fixme: is this needed? 631 //&& ! state.upgrade 632 && state.get_shared_count() == 1) 633 break; 634 if(status == cv_status::timeout) 635 return false; 636 } 637 } 638 state.unlock_shared(); 639 state.lock(); 640 state.upgrade=false; // Is this absolutely needed? 641 state.exclusive_waiting_blocked=false; // Is this absolutely needed? 642 return true; 643 } 644 #endif 645 #endif 646 647 // Shared <-> Upgrade unlock_upgrade_and_lock_shared()648 void unlock_upgrade_and_lock_shared() 649 { 650 boost::unique_lock<boost::mutex> lk(state_change); 651 state.assert_lock_upgraded(); 652 //state.unlock_upgrade(); 653 //state.lock_shared(); // less efficient 654 state.upgrade=false; 655 state.exclusive_waiting_blocked=false; // Is this absolutely needed? 656 release_waiters(); 657 } 658 659 #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS try_unlock_shared_and_lock_upgrade()660 bool try_unlock_shared_and_lock_upgrade() 661 { 662 boost::unique_lock<boost::mutex> lk(state_change); 663 state.assert_lock_shared(); 664 if( //! state.exclusive // this should be removed once the assertion work 665 ! state.exclusive_waiting_blocked // Fixme: is this needed? 666 && ! state.upgrade 667 ) 668 { 669 state.upgrade=true; 670 return true; 671 } 672 return false; 673 } 674 #ifdef BOOST_THREAD_USES_CHRONO 675 template <class Rep, class Period> 676 bool try_unlock_shared_and_lock_upgrade_for(const chrono::duration<Rep,Period> & rel_time)677 try_unlock_shared_and_lock_upgrade_for( 678 const chrono::duration<Rep, Period>& rel_time) 679 { 680 return try_unlock_shared_and_lock_upgrade_until( 681 chrono::steady_clock::now() + rel_time); 682 } 683 template <class Clock, class Duration> 684 bool try_unlock_shared_and_lock_upgrade_until(const chrono::time_point<Clock,Duration> & abs_time)685 try_unlock_shared_and_lock_upgrade_until( 686 const chrono::time_point<Clock, Duration>& abs_time) 687 { 688 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 689 boost::this_thread::disable_interruption do_not_disturb; 690 #endif 691 boost::unique_lock<boost::mutex> lk(state_change); 692 state.assert_lock_shared(); 693 if( //state.exclusive // this should be removed once the assertion work 694 state.exclusive_waiting_blocked // Fixme: is this needed? 695 || state.upgrade 696 ) 697 { 698 for (;;) 699 { 700 cv_status status = exclusive_cond.wait_until(lk,abs_time); 701 if( //! state.exclusive // this should be removed once the assertion work 702 ! state.exclusive_waiting_blocked // Fixme: is this needed? 703 && ! state.upgrade 704 ) 705 break; 706 if(status == cv_status::timeout) 707 return false; 708 } 709 } 710 //state.unlock_shared(); 711 //state.lock_upgrade(); // less efficient 712 state.upgrade=true; 713 return true; 714 } 715 #endif 716 #endif 717 }; 718 719 typedef shared_mutex upgrade_mutex; 720 } 721 722 #include <boost/config/abi_suffix.hpp> 723 724 #endif 725