1 #ifndef BOOST_THREAD_V2_SHARED_MUTEX_HPP 2 #define BOOST_THREAD_V2_SHARED_MUTEX_HPP 3 4 // shared_mutex.hpp 5 // 6 // Copyright Howard Hinnant 2007-2010. 7 // Copyright Vicente J. Botet Escriba 2012. 8 // 9 // Distributed under the Boost Software License, Version 1.0. (See 10 // accompanying file LICENSE_1_0.txt or copy at 11 // http://www.boost.org/LICENSE_1_0.txt) 12 13 /* 14 <shared_mutex> synopsis 15 16 namespace boost 17 { 18 namespace thread_v2 19 { 20 21 class shared_mutex 22 { 23 public: 24 25 shared_mutex(); 26 ~shared_mutex(); 27 28 shared_mutex(const shared_mutex&) = delete; 29 shared_mutex& operator=(const shared_mutex&) = delete; 30 31 // Exclusive ownership 32 33 void lock(); 34 bool try_lock(); 35 template <class Rep, class Period> 36 bool try_lock_for(const boost::chrono::duration<Rep, Period>& rel_time); 37 template <class Clock, class Duration> 38 bool 39 try_lock_until( 40 const boost::chrono::time_point<Clock, Duration>& abs_time); 41 void unlock(); 42 43 // Shared ownership 44 45 void lock_shared(); 46 bool try_lock_shared(); 47 template <class Rep, class Period> 48 bool 49 try_lock_shared_for(const boost::chrono::duration<Rep, Period>& rel_time); 50 template <class Clock, class Duration> 51 bool 52 try_lock_shared_until( 53 const boost::chrono::time_point<Clock, Duration>& abs_time); 54 void unlock_shared(); 55 }; 56 57 class upgrade_mutex 58 { 59 public: 60 61 upgrade_mutex(); 62 ~upgrade_mutex(); 63 64 upgrade_mutex(const upgrade_mutex&) = delete; 65 upgrade_mutex& operator=(const upgrade_mutex&) = delete; 66 67 // Exclusive ownership 68 69 void lock(); 70 bool try_lock(); 71 template <class Rep, class Period> 72 bool try_lock_for(const boost::chrono::duration<Rep, Period>& rel_time); 73 template <class Clock, class Duration> 74 bool 75 try_lock_until( 76 const boost::chrono::time_point<Clock, Duration>& abs_time); 77 void unlock(); 78 79 // Shared ownership 80 81 void lock_shared(); 82 bool try_lock_shared(); 83 template <class Rep, class Period> 84 bool 85 try_lock_shared_for(const boost::chrono::duration<Rep, Period>& rel_time); 86 template <class Clock, class Duration> 87 bool 88 try_lock_shared_until( 89 const boost::chrono::time_point<Clock, Duration>& abs_time); 90 void unlock_shared(); 91 92 // Upgrade ownership 93 94 void lock_upgrade(); 95 bool try_lock_upgrade(); 96 template <class Rep, class Period> 97 bool 98 try_lock_upgrade_for( 99 const boost::chrono::duration<Rep, Period>& rel_time); 100 template <class Clock, class Duration> 101 bool 102 try_lock_upgrade_until( 103 const boost::chrono::time_point<Clock, Duration>& abs_time); 104 void unlock_upgrade(); 105 106 // Shared <-> Exclusive 107 108 bool try_unlock_shared_and_lock(); 109 template <class Rep, class Period> 110 bool 111 try_unlock_shared_and_lock_for( 112 const boost::chrono::duration<Rep, Period>& rel_time); 113 template <class Clock, class Duration> 114 bool 115 try_unlock_shared_and_lock_until( 116 const boost::chrono::time_point<Clock, Duration>& abs_time); 117 void unlock_and_lock_shared(); 118 119 // Shared <-> Upgrade 120 121 bool try_unlock_shared_and_lock_upgrade(); 122 template <class Rep, class Period> 123 bool 124 try_unlock_shared_and_lock_upgrade_for( 125 const boost::chrono::duration<Rep, Period>& rel_time); 126 template <class Clock, class Duration> 127 bool 128 try_unlock_shared_and_lock_upgrade_until( 129 const boost::chrono::time_point<Clock, Duration>& abs_time); 130 void unlock_upgrade_and_lock_shared(); 131 132 // Upgrade <-> Exclusive 133 134 void unlock_upgrade_and_lock(); 135 bool try_unlock_upgrade_and_lock(); 136 template <class Rep, class Period> 137 bool 138 try_unlock_upgrade_and_lock_for( 139 const boost::chrono::duration<Rep, Period>& rel_time); 140 template <class Clock, class Duration> 141 bool 142 try_unlock_upgrade_and_lock_until( 143 const boost::chrono::time_point<Clock, Duration>& abs_time); 144 void unlock_and_lock_upgrade(); 145 }; 146 147 } // thread_v2 148 } // boost 149 150 */ 151 152 #include <boost/thread/detail/config.hpp> 153 #include <boost/thread/mutex.hpp> 154 #include <boost/thread/condition_variable.hpp> 155 #include <boost/thread/mutex.hpp> 156 #ifdef BOOST_THREAD_USES_CHRONO 157 #include <boost/chrono.hpp> 158 #endif 159 #include <climits> 160 #include <boost/system/system_error.hpp> 161 #include <boost/bind/bind.hpp> 162 163 namespace boost { 164 namespace thread_v2 { 165 166 class shared_mutex 167 { 168 typedef boost::mutex mutex_t; 169 typedef boost::condition_variable cond_t; 170 typedef unsigned count_t; 171 172 mutex_t mut_; 173 cond_t gate1_; 174 // the gate2_ condition variable is only used by functions that 175 // have taken write_entered_ but are waiting for no_readers() 176 cond_t gate2_; 177 count_t state_; 178 179 static const count_t write_entered_ = 1U << (sizeof(count_t)*CHAR_BIT - 1); 180 static const count_t n_readers_ = ~write_entered_; 181 no_writer() const182 bool no_writer() const 183 { 184 return (state_ & write_entered_) == 0; 185 } 186 one_writer() const187 bool one_writer() const 188 { 189 return (state_ & write_entered_) != 0; 190 } 191 no_writer_no_readers() const192 bool no_writer_no_readers() const 193 { 194 //return (state_ & write_entered_) == 0 && 195 // (state_ & n_readers_) == 0; 196 return state_ == 0; 197 } 198 no_writer_no_max_readers() const199 bool no_writer_no_max_readers() const 200 { 201 return (state_ & write_entered_) == 0 && 202 (state_ & n_readers_) != n_readers_; 203 } 204 no_readers() const205 bool no_readers() const 206 { 207 return (state_ & n_readers_) == 0; 208 } 209 one_or_more_readers() const210 bool one_or_more_readers() const 211 { 212 return (state_ & n_readers_) > 0; 213 } 214 215 shared_mutex(shared_mutex const&); 216 shared_mutex& operator=(shared_mutex const&); 217 218 public: 219 shared_mutex(); 220 ~shared_mutex(); 221 222 // Exclusive ownership 223 224 void lock(); 225 bool try_lock(); 226 #ifdef BOOST_THREAD_USES_CHRONO 227 template <class Rep, class Period> try_lock_for(const boost::chrono::duration<Rep,Period> & rel_time)228 bool try_lock_for(const boost::chrono::duration<Rep, Period>& rel_time) 229 { 230 return try_lock_until(chrono::steady_clock::now() + rel_time); 231 } 232 template <class Clock, class Duration> 233 bool try_lock_until( 234 const boost::chrono::time_point<Clock, Duration>& abs_time); 235 #endif 236 #if defined BOOST_THREAD_USES_DATETIME 237 template<typename T> 238 bool timed_lock(T const & abs_or_rel_time); 239 #endif 240 void unlock(); 241 242 // Shared ownership 243 244 void lock_shared(); 245 bool try_lock_shared(); 246 #ifdef BOOST_THREAD_USES_CHRONO 247 template <class Rep, class Period> try_lock_shared_for(const boost::chrono::duration<Rep,Period> & rel_time)248 bool try_lock_shared_for(const boost::chrono::duration<Rep, Period>& rel_time) 249 { 250 return try_lock_shared_until(chrono::steady_clock::now() + rel_time); 251 } 252 template <class Clock, class Duration> 253 bool try_lock_shared_until( 254 const boost::chrono::time_point<Clock, Duration>& abs_time); 255 #endif 256 #if defined BOOST_THREAD_USES_DATETIME 257 template<typename T> 258 bool timed_lock_shared(T const & abs_or_rel_time); 259 #endif 260 void unlock_shared(); 261 }; 262 shared_mutex()263 inline shared_mutex::shared_mutex() 264 : state_(0) 265 { 266 } 267 ~shared_mutex()268 inline shared_mutex::~shared_mutex() 269 { 270 boost::lock_guard<mutex_t> _(mut_); 271 } 272 273 // Exclusive ownership 274 lock()275 inline void shared_mutex::lock() 276 { 277 boost::unique_lock<mutex_t> lk(mut_); 278 gate1_.wait(lk, boost::bind(&shared_mutex::no_writer, boost::ref(*this))); 279 state_ |= write_entered_; 280 gate2_.wait(lk, boost::bind(&shared_mutex::no_readers, boost::ref(*this))); 281 } 282 try_lock()283 inline bool shared_mutex::try_lock() 284 { 285 boost::unique_lock<mutex_t> lk(mut_); 286 if (!no_writer_no_readers()) 287 { 288 return false; 289 } 290 state_ = write_entered_; 291 return true; 292 } 293 294 #ifdef BOOST_THREAD_USES_CHRONO 295 template <class Clock, class Duration> try_lock_until(const boost::chrono::time_point<Clock,Duration> & abs_time)296 bool shared_mutex::try_lock_until( 297 const boost::chrono::time_point<Clock, Duration>& abs_time) 298 { 299 boost::unique_lock<mutex_t> lk(mut_); 300 if (!gate1_.wait_until(lk, abs_time, boost::bind( 301 &shared_mutex::no_writer, boost::ref(*this)))) 302 { 303 return false; 304 } 305 state_ |= write_entered_; 306 if (!gate2_.wait_until(lk, abs_time, boost::bind( 307 &shared_mutex::no_readers, boost::ref(*this)))) 308 { 309 state_ &= ~write_entered_; 310 return false; 311 } 312 return true; 313 } 314 #endif 315 316 #if defined BOOST_THREAD_USES_DATETIME 317 template<typename T> timed_lock(T const & abs_or_rel_time)318 bool shared_mutex::timed_lock(T const & abs_or_rel_time) 319 { 320 boost::unique_lock<mutex_t> lk(mut_); 321 if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind( 322 &shared_mutex::no_writer, boost::ref(*this)))) 323 { 324 return false; 325 } 326 state_ |= write_entered_; 327 if (!gate2_.timed_wait(lk, abs_or_rel_time, boost::bind( 328 &shared_mutex::no_readers, boost::ref(*this)))) 329 { 330 state_ &= ~write_entered_; 331 return false; 332 } 333 return true; 334 } 335 #endif 336 unlock()337 inline void shared_mutex::unlock() 338 { 339 boost::lock_guard<mutex_t> _(mut_); 340 BOOST_ASSERT(one_writer()); 341 BOOST_ASSERT(no_readers()); 342 state_ = 0; 343 // notify all since multiple *lock_shared*() calls may be able 344 // to proceed in response to this notification 345 gate1_.notify_all(); 346 } 347 348 // Shared ownership 349 lock_shared()350 inline void shared_mutex::lock_shared() 351 { 352 boost::unique_lock<mutex_t> lk(mut_); 353 gate1_.wait(lk, boost::bind(&shared_mutex::no_writer_no_max_readers, boost::ref(*this))); 354 count_t num_readers = (state_ & n_readers_) + 1; 355 state_ &= ~n_readers_; 356 state_ |= num_readers; 357 } 358 try_lock_shared()359 inline bool shared_mutex::try_lock_shared() 360 { 361 boost::unique_lock<mutex_t> lk(mut_); 362 if (!no_writer_no_max_readers()) 363 { 364 return false; 365 } 366 count_t num_readers = (state_ & n_readers_) + 1; 367 state_ &= ~n_readers_; 368 state_ |= num_readers; 369 return true; 370 } 371 372 #ifdef BOOST_THREAD_USES_CHRONO 373 template <class Clock, class Duration> try_lock_shared_until(const boost::chrono::time_point<Clock,Duration> & abs_time)374 bool shared_mutex::try_lock_shared_until( 375 const boost::chrono::time_point<Clock, Duration>& abs_time) 376 { 377 boost::unique_lock<mutex_t> lk(mut_); 378 if (!gate1_.wait_until(lk, abs_time, boost::bind( 379 &shared_mutex::no_writer_no_max_readers, boost::ref(*this)))) 380 { 381 return false; 382 } 383 count_t num_readers = (state_ & n_readers_) + 1; 384 state_ &= ~n_readers_; 385 state_ |= num_readers; 386 return true; 387 } 388 #endif 389 390 #if defined BOOST_THREAD_USES_DATETIME 391 template<typename T> timed_lock_shared(T const & abs_or_rel_time)392 bool shared_mutex::timed_lock_shared(T const & abs_or_rel_time) 393 { 394 boost::unique_lock<mutex_t> lk(mut_); 395 if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind( 396 &shared_mutex::no_writer_no_max_readers, boost::ref(*this)))) 397 { 398 return false; 399 } 400 count_t num_readers = (state_ & n_readers_) + 1; 401 state_ &= ~n_readers_; 402 state_ |= num_readers; 403 return true; 404 } 405 #endif 406 unlock_shared()407 inline void shared_mutex::unlock_shared() 408 { 409 boost::lock_guard<mutex_t> _(mut_); 410 BOOST_ASSERT(one_or_more_readers()); 411 count_t num_readers = (state_ & n_readers_) - 1; 412 state_ &= ~n_readers_; 413 state_ |= num_readers; 414 if (no_writer()) 415 { 416 if (num_readers == n_readers_ - 1) 417 gate1_.notify_one(); 418 } 419 else 420 { 421 if (num_readers == 0) 422 gate2_.notify_one(); 423 } 424 } 425 426 } // thread_v2 427 } // boost 428 429 namespace boost { 430 namespace thread_v2 { 431 432 class upgrade_mutex 433 { 434 typedef boost::mutex mutex_t; 435 typedef boost::condition_variable cond_t; 436 typedef unsigned count_t; 437 438 mutex_t mut_; 439 cond_t gate1_; 440 // the gate2_ condition variable is only used by functions that 441 // have taken write_entered_ but are waiting for no_readers() 442 cond_t gate2_; 443 count_t state_; 444 445 static const unsigned write_entered_ = 1U << (sizeof(count_t)*CHAR_BIT - 1); 446 static const unsigned upgradable_entered_ = write_entered_ >> 1; 447 static const unsigned n_readers_ = ~(write_entered_ | upgradable_entered_); 448 no_writer() const449 bool no_writer() const 450 { 451 return (state_ & write_entered_) == 0; 452 } 453 one_writer() const454 bool one_writer() const 455 { 456 return (state_ & write_entered_) != 0; 457 } 458 no_writer_no_max_readers() const459 bool no_writer_no_max_readers() const 460 { 461 return (state_ & write_entered_) == 0 && 462 (state_ & n_readers_) != n_readers_; 463 } 464 no_writer_no_upgrader() const465 bool no_writer_no_upgrader() const 466 { 467 return (state_ & (write_entered_ | upgradable_entered_)) == 0; 468 } 469 no_writer_no_upgrader_no_readers() const470 bool no_writer_no_upgrader_no_readers() const 471 { 472 //return (state_ & (write_entered_ | upgradable_entered_)) == 0 && 473 // (state_ & n_readers_) == 0; 474 return state_ == 0; 475 } 476 no_writer_no_upgrader_one_reader() const477 bool no_writer_no_upgrader_one_reader() const 478 { 479 //return (state_ & (write_entered_ | upgradable_entered_)) == 0 && 480 // (state_ & n_readers_) == 1; 481 return state_ == 1; 482 } 483 no_writer_no_upgrader_no_max_readers() const484 bool no_writer_no_upgrader_no_max_readers() const 485 { 486 return (state_ & (write_entered_ | upgradable_entered_)) == 0 && 487 (state_ & n_readers_) != n_readers_; 488 } 489 no_upgrader() const490 bool no_upgrader() const 491 { 492 return (state_ & upgradable_entered_) == 0; 493 } 494 one_upgrader() const495 bool one_upgrader() const 496 { 497 return (state_ & upgradable_entered_) != 0; 498 } 499 no_readers() const500 bool no_readers() const 501 { 502 return (state_ & n_readers_) == 0; 503 } 504 one_reader() const505 bool one_reader() const 506 { 507 return (state_ & n_readers_) == 1; 508 } 509 one_or_more_readers() const510 bool one_or_more_readers() const 511 { 512 return (state_ & n_readers_) > 0; 513 } 514 515 upgrade_mutex(const upgrade_mutex&); 516 upgrade_mutex& operator=(const upgrade_mutex&); 517 518 public: 519 upgrade_mutex(); 520 ~upgrade_mutex(); 521 522 // Exclusive ownership 523 524 void lock(); 525 bool try_lock(); 526 #ifdef BOOST_THREAD_USES_CHRONO 527 template <class Rep, class Period> try_lock_for(const boost::chrono::duration<Rep,Period> & rel_time)528 bool try_lock_for(const boost::chrono::duration<Rep, Period>& rel_time) 529 { 530 return try_lock_until(chrono::steady_clock::now() + rel_time); 531 } 532 template <class Clock, class Duration> 533 bool try_lock_until( 534 const boost::chrono::time_point<Clock, Duration>& abs_time); 535 #endif 536 #if defined BOOST_THREAD_USES_DATETIME 537 template<typename T> 538 bool timed_lock(T const & abs_or_rel_time); 539 #endif 540 void unlock(); 541 542 // Shared ownership 543 544 void lock_shared(); 545 bool try_lock_shared(); 546 #ifdef BOOST_THREAD_USES_CHRONO 547 template <class Rep, class Period> try_lock_shared_for(const boost::chrono::duration<Rep,Period> & rel_time)548 bool try_lock_shared_for(const boost::chrono::duration<Rep, Period>& rel_time) 549 { 550 return try_lock_shared_until(chrono::steady_clock::now() + rel_time); 551 } 552 template <class Clock, class Duration> 553 bool try_lock_shared_until( 554 const boost::chrono::time_point<Clock, Duration>& abs_time); 555 #endif 556 #if defined BOOST_THREAD_USES_DATETIME 557 template<typename T> 558 bool timed_lock_shared(T const & abs_or_rel_time); 559 #endif 560 void unlock_shared(); 561 562 // Upgrade ownership 563 564 void lock_upgrade(); 565 bool try_lock_upgrade(); 566 #ifdef BOOST_THREAD_USES_CHRONO 567 template <class Rep, class Period> try_lock_upgrade_for(const boost::chrono::duration<Rep,Period> & rel_time)568 bool try_lock_upgrade_for( 569 const boost::chrono::duration<Rep, Period>& rel_time) 570 { 571 return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time); 572 } 573 template <class Clock, class Duration> 574 bool try_lock_upgrade_until( 575 const boost::chrono::time_point<Clock, Duration>& abs_time); 576 #endif 577 #if defined BOOST_THREAD_USES_DATETIME 578 template<typename T> 579 bool timed_lock_upgrade(T const & abs_or_rel_time); 580 #endif 581 void unlock_upgrade(); 582 583 // Shared <-> Exclusive 584 585 #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS 586 //bool unlock_shared_and_lock(); // can cause a deadlock if used 587 bool try_unlock_shared_and_lock(); 588 #ifdef BOOST_THREAD_USES_CHRONO 589 template <class Rep, class Period> try_unlock_shared_and_lock_for(const boost::chrono::duration<Rep,Period> & rel_time)590 bool try_unlock_shared_and_lock_for( 591 const boost::chrono::duration<Rep, Period>& rel_time) 592 { 593 return try_unlock_shared_and_lock_until(chrono::steady_clock::now() + rel_time); 594 } 595 template <class Clock, class Duration> 596 bool try_unlock_shared_and_lock_until( 597 const boost::chrono::time_point<Clock, Duration>& abs_time); 598 #endif 599 #endif 600 void unlock_and_lock_shared(); 601 602 // Shared <-> Upgrade 603 604 #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS 605 //bool unlock_shared_and_lock_upgrade(); // can cause a deadlock if used 606 bool try_unlock_shared_and_lock_upgrade(); 607 #ifdef BOOST_THREAD_USES_CHRONO 608 template <class Rep, class Period> try_unlock_shared_and_lock_upgrade_for(const boost::chrono::duration<Rep,Period> & rel_time)609 bool try_unlock_shared_and_lock_upgrade_for( 610 const boost::chrono::duration<Rep, Period>& rel_time) 611 { 612 return try_unlock_shared_and_lock_upgrade_until(chrono::steady_clock::now() + rel_time); 613 } 614 template <class Clock, class Duration> 615 bool try_unlock_shared_and_lock_upgrade_until( 616 const boost::chrono::time_point<Clock, Duration>& abs_time); 617 #endif 618 #endif 619 void unlock_upgrade_and_lock_shared(); 620 621 // Upgrade <-> Exclusive 622 623 void unlock_upgrade_and_lock(); 624 bool try_unlock_upgrade_and_lock(); 625 #ifdef BOOST_THREAD_USES_CHRONO 626 template <class Rep, class Period> try_unlock_upgrade_and_lock_for(const boost::chrono::duration<Rep,Period> & rel_time)627 bool try_unlock_upgrade_and_lock_for( 628 const boost::chrono::duration<Rep, Period>& rel_time) 629 { 630 return try_unlock_upgrade_and_lock_until(chrono::steady_clock::now() + rel_time); 631 } 632 template <class Clock, class Duration> 633 bool try_unlock_upgrade_and_lock_until( 634 const boost::chrono::time_point<Clock, Duration>& abs_time); 635 #endif 636 void unlock_and_lock_upgrade(); 637 }; 638 upgrade_mutex()639 inline upgrade_mutex::upgrade_mutex() 640 : gate1_(), 641 gate2_(), 642 state_(0) 643 { 644 } 645 ~upgrade_mutex()646 inline upgrade_mutex::~upgrade_mutex() 647 { 648 boost::lock_guard<mutex_t> _(mut_); 649 } 650 651 // Exclusive ownership 652 lock()653 inline void upgrade_mutex::lock() 654 { 655 boost::unique_lock<mutex_t> lk(mut_); 656 gate1_.wait(lk, boost::bind(&upgrade_mutex::no_writer_no_upgrader, boost::ref(*this))); 657 state_ |= write_entered_; 658 gate2_.wait(lk, boost::bind(&upgrade_mutex::no_readers, boost::ref(*this))); 659 } 660 try_lock()661 inline bool upgrade_mutex::try_lock() 662 { 663 boost::unique_lock<mutex_t> lk(mut_); 664 if (!no_writer_no_upgrader_no_readers()) 665 { 666 return false; 667 } 668 state_ = write_entered_; 669 return true; 670 } 671 672 #ifdef BOOST_THREAD_USES_CHRONO 673 template <class Clock, class Duration> try_lock_until(const boost::chrono::time_point<Clock,Duration> & abs_time)674 bool upgrade_mutex::try_lock_until( 675 const boost::chrono::time_point<Clock, Duration>& abs_time) 676 { 677 boost::unique_lock<mutex_t> lk(mut_); 678 if (!gate1_.wait_until(lk, abs_time, boost::bind( 679 &upgrade_mutex::no_writer_no_upgrader, boost::ref(*this)))) 680 { 681 return false; 682 } 683 state_ |= write_entered_; 684 if (!gate2_.wait_until(lk, abs_time, boost::bind( 685 &upgrade_mutex::no_readers, boost::ref(*this)))) 686 { 687 state_ &= ~write_entered_; 688 return false; 689 } 690 return true; 691 } 692 #endif 693 694 #if defined BOOST_THREAD_USES_DATETIME 695 template<typename T> timed_lock(T const & abs_or_rel_time)696 bool upgrade_mutex::timed_lock(T const & abs_or_rel_time) 697 { 698 boost::unique_lock<mutex_t> lk(mut_); 699 if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind( 700 &upgrade_mutex::no_writer_no_upgrader, boost::ref(*this)))) 701 { 702 return false; 703 } 704 state_ |= write_entered_; 705 if (!gate2_.timed_wait(lk, abs_or_rel_time, boost::bind( 706 &upgrade_mutex::no_readers, boost::ref(*this)))) 707 { 708 state_ &= ~write_entered_; 709 return false; 710 } 711 return true; 712 } 713 #endif 714 unlock()715 inline void upgrade_mutex::unlock() 716 { 717 boost::lock_guard<mutex_t> _(mut_); 718 BOOST_ASSERT(one_writer()); 719 BOOST_ASSERT(no_upgrader()); 720 BOOST_ASSERT(no_readers()); 721 state_ = 0; 722 // notify all since multiple *lock_shared*() calls and a *lock_upgrade*() 723 // call may be able to proceed in response to this notification 724 gate1_.notify_all(); 725 } 726 727 // Shared ownership 728 lock_shared()729 inline void upgrade_mutex::lock_shared() 730 { 731 boost::unique_lock<mutex_t> lk(mut_); 732 gate1_.wait(lk, boost::bind(&upgrade_mutex::no_writer_no_max_readers, boost::ref(*this))); 733 count_t num_readers = (state_ & n_readers_) + 1; 734 state_ &= ~n_readers_; 735 state_ |= num_readers; 736 } 737 try_lock_shared()738 inline bool upgrade_mutex::try_lock_shared() 739 { 740 boost::unique_lock<mutex_t> lk(mut_); 741 if (!no_writer_no_max_readers()) 742 { 743 return false; 744 } 745 count_t num_readers = (state_ & n_readers_) + 1; 746 state_ &= ~n_readers_; 747 state_ |= num_readers; 748 return true; 749 } 750 751 #ifdef BOOST_THREAD_USES_CHRONO 752 template <class Clock, class Duration> try_lock_shared_until(const boost::chrono::time_point<Clock,Duration> & abs_time)753 bool upgrade_mutex::try_lock_shared_until( 754 const boost::chrono::time_point<Clock, Duration>& abs_time) 755 { 756 boost::unique_lock<mutex_t> lk(mut_); 757 if (!gate1_.wait_until(lk, abs_time, boost::bind( 758 &upgrade_mutex::no_writer_no_max_readers, boost::ref(*this)))) 759 { 760 return false; 761 } 762 count_t num_readers = (state_ & n_readers_) + 1; 763 state_ &= ~n_readers_; 764 state_ |= num_readers; 765 return true; 766 } 767 #endif 768 769 #if defined BOOST_THREAD_USES_DATETIME 770 template<typename T> timed_lock_shared(T const & abs_or_rel_time)771 bool upgrade_mutex::timed_lock_shared(T const & abs_or_rel_time) 772 { 773 boost::unique_lock<mutex_t> lk(mut_); 774 if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind( 775 &upgrade_mutex::no_writer_no_max_readers, boost::ref(*this)))) 776 { 777 return false; 778 } 779 count_t num_readers = (state_ & n_readers_) + 1; 780 state_ &= ~n_readers_; 781 state_ |= num_readers; 782 return true; 783 } 784 #endif 785 unlock_shared()786 inline void upgrade_mutex::unlock_shared() 787 { 788 boost::lock_guard<mutex_t> _(mut_); 789 BOOST_ASSERT(one_or_more_readers()); 790 count_t num_readers = (state_ & n_readers_) - 1; 791 state_ &= ~n_readers_; 792 state_ |= num_readers; 793 if (no_writer()) 794 { 795 if (num_readers == n_readers_ - 1) 796 gate1_.notify_one(); 797 } 798 else 799 { 800 if (num_readers == 0) 801 gate2_.notify_one(); 802 } 803 } 804 805 // Upgrade ownership 806 lock_upgrade()807 inline void upgrade_mutex::lock_upgrade() 808 { 809 boost::unique_lock<mutex_t> lk(mut_); 810 gate1_.wait(lk, boost::bind(&upgrade_mutex::no_writer_no_upgrader_no_max_readers, boost::ref(*this))); 811 count_t num_readers = (state_ & n_readers_) + 1; 812 state_ &= ~n_readers_; 813 state_ |= upgradable_entered_ | num_readers; 814 } 815 try_lock_upgrade()816 inline bool upgrade_mutex::try_lock_upgrade() 817 { 818 boost::unique_lock<mutex_t> lk(mut_); 819 if (!no_writer_no_upgrader_no_max_readers()) 820 { 821 return false; 822 } 823 count_t num_readers = (state_ & n_readers_) + 1; 824 state_ &= ~n_readers_; 825 state_ |= upgradable_entered_ | num_readers; 826 return true; 827 } 828 829 #ifdef BOOST_THREAD_USES_CHRONO 830 template <class Clock, class Duration> try_lock_upgrade_until(const boost::chrono::time_point<Clock,Duration> & abs_time)831 bool upgrade_mutex::try_lock_upgrade_until( 832 const boost::chrono::time_point<Clock, Duration>& abs_time) 833 { 834 boost::unique_lock<mutex_t> lk(mut_); 835 if (!gate1_.wait_until(lk, abs_time, boost::bind( 836 &upgrade_mutex::no_writer_no_upgrader_no_max_readers, boost::ref(*this)))) 837 { 838 return false; 839 } 840 count_t num_readers = (state_ & n_readers_) + 1; 841 state_ &= ~n_readers_; 842 state_ |= upgradable_entered_ | num_readers; 843 return true; 844 } 845 #endif 846 847 #if defined BOOST_THREAD_USES_DATETIME 848 template<typename T> timed_lock_upgrade(T const & abs_or_rel_time)849 bool upgrade_mutex::timed_lock_upgrade(T const & abs_or_rel_time) 850 { 851 boost::unique_lock<mutex_t> lk(mut_); 852 if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind( 853 &upgrade_mutex::no_writer_no_upgrader_no_max_readers, boost::ref(*this)))) 854 { 855 return false; 856 } 857 count_t num_readers = (state_ & n_readers_) + 1; 858 state_ &= ~n_readers_; 859 state_ |= upgradable_entered_ | num_readers; 860 return true; 861 } 862 #endif 863 unlock_upgrade()864 inline void upgrade_mutex::unlock_upgrade() 865 { 866 boost::lock_guard<mutex_t> _(mut_); 867 BOOST_ASSERT(no_writer()); 868 BOOST_ASSERT(one_upgrader()); 869 BOOST_ASSERT(one_or_more_readers()); 870 count_t num_readers = (state_ & n_readers_) - 1; 871 state_ &= ~(upgradable_entered_ | n_readers_); 872 state_ |= num_readers; 873 // notify all since both a *lock*() and a *lock_shared*() call 874 // may be able to proceed in response to this notification 875 gate1_.notify_all(); 876 } 877 878 // Shared <-> Exclusive 879 880 #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS try_unlock_shared_and_lock()881 inline bool upgrade_mutex::try_unlock_shared_and_lock() 882 { 883 boost::unique_lock<mutex_t> lk(mut_); 884 BOOST_ASSERT(one_or_more_readers()); 885 if (!no_writer_no_upgrader_one_reader()) 886 { 887 return false; 888 } 889 state_ = write_entered_; 890 return true; 891 } 892 893 #ifdef BOOST_THREAD_USES_CHRONO 894 template <class Clock, class Duration> try_unlock_shared_and_lock_until(const boost::chrono::time_point<Clock,Duration> & abs_time)895 bool upgrade_mutex::try_unlock_shared_and_lock_until( 896 const boost::chrono::time_point<Clock, Duration>& abs_time) 897 { 898 boost::unique_lock<mutex_t> lk(mut_); 899 BOOST_ASSERT(one_or_more_readers()); 900 if (!gate1_.wait_until(lk, abs_time, boost::bind( 901 &upgrade_mutex::no_writer_no_upgrader, boost::ref(*this)))) 902 { 903 return false; 904 } 905 count_t num_readers = (state_ & n_readers_) - 1; 906 state_ &= ~n_readers_; 907 state_ |= (write_entered_ | num_readers); 908 if (!gate2_.wait_until(lk, abs_time, boost::bind( 909 &upgrade_mutex::no_readers, boost::ref(*this)))) 910 { 911 ++num_readers; 912 state_ &= ~(write_entered_ | n_readers_); 913 state_ |= num_readers; 914 return false; 915 } 916 return true; 917 } 918 #endif 919 #endif 920 unlock_and_lock_shared()921 inline void upgrade_mutex::unlock_and_lock_shared() 922 { 923 boost::lock_guard<mutex_t> _(mut_); 924 BOOST_ASSERT(one_writer()); 925 BOOST_ASSERT(no_upgrader()); 926 BOOST_ASSERT(no_readers()); 927 state_ = 1; 928 // notify all since multiple *lock_shared*() calls and a *lock_upgrade*() 929 // call may be able to proceed in response to this notification 930 gate1_.notify_all(); 931 } 932 933 // Shared <-> Upgrade 934 935 #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS try_unlock_shared_and_lock_upgrade()936 inline bool upgrade_mutex::try_unlock_shared_and_lock_upgrade() 937 { 938 boost::unique_lock<mutex_t> lk(mut_); 939 BOOST_ASSERT(one_or_more_readers()); 940 if (!no_writer_no_upgrader()) 941 { 942 return false; 943 } 944 state_ |= upgradable_entered_; 945 return true; 946 } 947 948 #ifdef BOOST_THREAD_USES_CHRONO 949 template <class Clock, class Duration> try_unlock_shared_and_lock_upgrade_until(const boost::chrono::time_point<Clock,Duration> & abs_time)950 bool upgrade_mutex::try_unlock_shared_and_lock_upgrade_until( 951 const boost::chrono::time_point<Clock, Duration>& abs_time) 952 { 953 boost::unique_lock<mutex_t> lk(mut_); 954 BOOST_ASSERT(one_or_more_readers()); 955 if (!gate1_.wait_until(lk, abs_time, boost::bind( 956 &upgrade_mutex::no_writer_no_upgrader, boost::ref(*this)))) 957 { 958 return false; 959 } 960 state_ |= upgradable_entered_; 961 return true; 962 } 963 #endif 964 #endif 965 unlock_upgrade_and_lock_shared()966 inline void upgrade_mutex::unlock_upgrade_and_lock_shared() 967 { 968 boost::lock_guard<mutex_t> _(mut_); 969 BOOST_ASSERT(no_writer()); 970 BOOST_ASSERT(one_upgrader()); 971 BOOST_ASSERT(one_or_more_readers()); 972 state_ &= ~upgradable_entered_; 973 // notify all since only one *lock*() or *lock_upgrade*() call can win and 974 // proceed in response to this notification, but a *lock_shared*() call may 975 // also be waiting and could steal the notification 976 gate1_.notify_all(); 977 } 978 979 // Upgrade <-> Exclusive 980 unlock_upgrade_and_lock()981 inline void upgrade_mutex::unlock_upgrade_and_lock() 982 { 983 boost::unique_lock<mutex_t> lk(mut_); 984 BOOST_ASSERT(no_writer()); 985 BOOST_ASSERT(one_upgrader()); 986 BOOST_ASSERT(one_or_more_readers()); 987 count_t num_readers = (state_ & n_readers_) - 1; 988 state_ &= ~(upgradable_entered_ | n_readers_); 989 state_ |= write_entered_ | num_readers; 990 gate2_.wait(lk, boost::bind(&upgrade_mutex::no_readers, boost::ref(*this))); 991 } 992 try_unlock_upgrade_and_lock()993 inline bool upgrade_mutex::try_unlock_upgrade_and_lock() 994 { 995 boost::unique_lock<mutex_t> lk(mut_); 996 BOOST_ASSERT(no_writer()); 997 BOOST_ASSERT(one_upgrader()); 998 BOOST_ASSERT(one_or_more_readers()); 999 if (!one_reader()) 1000 { 1001 return false; 1002 } 1003 state_ = write_entered_; 1004 return true; 1005 } 1006 1007 #ifdef BOOST_THREAD_USES_CHRONO 1008 template <class Clock, class Duration> try_unlock_upgrade_and_lock_until(const boost::chrono::time_point<Clock,Duration> & abs_time)1009 bool upgrade_mutex::try_unlock_upgrade_and_lock_until( 1010 const boost::chrono::time_point<Clock, Duration>& abs_time) 1011 { 1012 boost::unique_lock<mutex_t> lk(mut_); 1013 BOOST_ASSERT(no_writer()); 1014 BOOST_ASSERT(one_upgrader()); 1015 BOOST_ASSERT(one_or_more_readers()); 1016 count_t num_readers = (state_ & n_readers_) - 1; 1017 state_ &= ~(upgradable_entered_ | n_readers_); 1018 state_ |= (write_entered_ | num_readers); 1019 if (!gate2_.wait_until(lk, abs_time, boost::bind( 1020 &upgrade_mutex::no_readers, boost::ref(*this)))) 1021 { 1022 ++num_readers; 1023 state_ &= ~(write_entered_ | n_readers_); 1024 state_ |= (upgradable_entered_ | num_readers); 1025 return false; 1026 } 1027 return true; 1028 } 1029 #endif 1030 unlock_and_lock_upgrade()1031 inline void upgrade_mutex::unlock_and_lock_upgrade() 1032 { 1033 boost::lock_guard<mutex_t> _(mut_); 1034 BOOST_ASSERT(one_writer()); 1035 BOOST_ASSERT(no_upgrader()); 1036 BOOST_ASSERT(no_readers()); 1037 state_ = upgradable_entered_ | 1; 1038 // notify all since multiple *lock_shared*() calls may be able 1039 // to proceed in response to this notification 1040 gate1_.notify_all(); 1041 } 1042 1043 } // thread_v2 1044 } // boost 1045 1046 namespace boost { 1047 //using thread_v2::shared_mutex; 1048 using thread_v2::upgrade_mutex; 1049 typedef thread_v2::upgrade_mutex shared_mutex; 1050 } 1051 1052 #endif 1053