1 #ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
2 #define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
4 // (C) Copyright 2006-8 Anthony Williams
5 // (C) Copyright 2012 Vicente J. Botet Escriba
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)
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>
18 #ifdef BOOST_THREAD_USES_CHRONO
19 #include <boost/chrono/system_clocks.hpp>
20 #include <boost/chrono/ceil.hpp>
22 #include <boost/thread/detail/delete.hpp>
23 #include <boost/assert.hpp>
25 #include <boost/config/abi_prefix.hpp>
39 exclusive_waiting_blocked(false)
42 void assert_free() const
44 BOOST_ASSERT( ! exclusive );
45 BOOST_ASSERT( ! upgrade );
46 BOOST_ASSERT( shared_count==0 );
49 void assert_locked() const
51 BOOST_ASSERT( exclusive );
52 BOOST_ASSERT( shared_count==0 );
53 BOOST_ASSERT( ! upgrade );
56 void assert_lock_shared () const
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.
65 void assert_lock_upgraded () const
67 BOOST_ASSERT( ! exclusive );
68 BOOST_ASSERT( upgrade );
69 BOOST_ASSERT( shared_count>0 );
72 void assert_lock_not_upgraded () const
74 BOOST_ASSERT( ! upgrade );
77 bool can_lock () const
79 return ! (shared_count || exclusive);
82 void exclusive_blocked (bool blocked)
84 exclusive_waiting_blocked = blocked;
95 exclusive_waiting_blocked = false;
98 bool can_lock_shared () const
100 return ! (exclusive || exclusive_waiting_blocked);
103 bool is_last_shared () const
105 return !shared_count ;
107 unsigned get_shared_count () const
109 return shared_count ;
111 unsigned lock_shared ()
113 return ++shared_count;
117 void unlock_shared ()
122 bool unlock_shared_downgrades()
129 exclusive_waiting_blocked=false;
139 bool can_lock_upgrade () const
141 return ! (exclusive || exclusive_waiting_blocked || upgrade);
144 void unlock_upgrade ()
151 unsigned shared_count;
154 bool exclusive_waiting_blocked;
160 boost::mutex state_change;
161 boost::condition_variable shared_cond;
162 boost::condition_variable exclusive_cond;
163 boost::condition_variable upgrade_cond;
165 void release_waiters()
167 exclusive_cond.notify_one();
168 shared_cond.notify_all();
172 BOOST_THREAD_NO_COPYABLE(shared_mutex)
184 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
185 boost::this_thread::disable_interruption do_not_disturb;
187 boost::unique_lock<boost::mutex> lk(state_change);
189 while(!state.can_lock_shared())
191 shared_cond.wait(lk);
196 bool try_lock_shared()
198 boost::unique_lock<boost::mutex> lk(state_change);
199 if(!state.can_lock_shared())
210 #if defined BOOST_THREAD_USES_DATETIME
211 bool timed_lock_shared(system_time const& timeout)
213 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
214 boost::this_thread::disable_interruption do_not_disturb;
216 boost::unique_lock<boost::mutex> lk(state_change);
218 while(!state.can_lock_shared())
220 if(!shared_cond.timed_wait(lk,timeout))
229 template<typename TimeDuration>
230 bool timed_lock_shared(TimeDuration const & relative_time)
232 return timed_lock_shared(get_system_time()+relative_time);
235 #ifdef BOOST_THREAD_USES_CHRONO
236 template <class Rep, class Period>
237 bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
239 return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
241 template <class Clock, class Duration>
242 bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time)
244 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
245 boost::this_thread::disable_interruption do_not_disturb;
247 boost::unique_lock<boost::mutex> lk(state_change);
249 while(!state.can_lock_shared())
251 if(cv_status::timeout==shared_cond.wait_until(lk,abs_time))
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)
267 if (state.unlock_shared_downgrades())
270 upgrade_cond.notify_one();
280 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
281 boost::this_thread::disable_interruption do_not_disturb;
283 boost::unique_lock<boost::mutex> lk(state_change);
285 while(!state.can_lock())
287 state.exclusive_blocked(true);
288 exclusive_cond.wait(lk);
293 #if defined BOOST_THREAD_USES_DATETIME
294 bool timed_lock(system_time const& timeout)
296 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
297 boost::this_thread::disable_interruption do_not_disturb;
299 boost::unique_lock<boost::mutex> lk(state_change);
301 while(!state.can_lock())
303 state.exclusive_blocked(true);
304 if(!exclusive_cond.timed_wait(lk,timeout))
306 if(!state.can_lock())
308 state.exclusive_blocked(false);
315 state.exclusive=true;
320 template<typename TimeDuration>
321 bool timed_lock(TimeDuration const & relative_time)
323 return timed_lock(get_system_time()+relative_time);
326 #ifdef BOOST_THREAD_USES_CHRONO
327 template <class Rep, class Period>
328 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
330 return try_lock_until(chrono::steady_clock::now() + rel_time);
332 template <class Clock, class Duration>
333 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
335 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
336 boost::this_thread::disable_interruption do_not_disturb;
338 boost::unique_lock<boost::mutex> lk(state_change);
340 while(!state.can_lock())
342 state.exclusive_blocked(true);
343 if(cv_status::timeout == exclusive_cond.wait_until(lk,abs_time))
345 if(!state.can_lock())
347 state.exclusive_blocked(false);
354 state.exclusive=true;
362 boost::unique_lock<boost::mutex> lk(state_change);
364 if(!state.can_lock())
378 boost::unique_lock<boost::mutex> lk(state_change);
379 state.assert_locked();
387 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
388 boost::this_thread::disable_interruption do_not_disturb;
390 boost::unique_lock<boost::mutex> lk(state_change);
391 while(!state.can_lock_upgrade())
393 shared_cond.wait(lk);
395 state.lock_upgrade();
398 #if defined BOOST_THREAD_USES_DATETIME
399 bool timed_lock_upgrade(system_time const& timeout)
401 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
402 boost::this_thread::disable_interruption do_not_disturb;
404 boost::unique_lock<boost::mutex> lk(state_change);
405 while(!state.can_lock_upgrade())
407 if(!shared_cond.timed_wait(lk,timeout))
409 if(!state.can_lock_upgrade())
416 state.lock_upgrade();
420 template<typename TimeDuration>
421 bool timed_lock_upgrade(TimeDuration const & relative_time)
423 return timed_lock_upgrade(get_system_time()+relative_time);
426 #ifdef BOOST_THREAD_USES_CHRONO
427 template <class Rep, class Period>
428 bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time)
430 return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time);
432 template <class Clock, class Duration>
433 bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time)
435 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
436 boost::this_thread::disable_interruption do_not_disturb;
438 boost::unique_lock<boost::mutex> lk(state_change);
439 while(!state.can_lock_upgrade())
441 if(cv_status::timeout == shared_cond.wait_until(lk,abs_time))
443 if(!state.can_lock_upgrade())
450 state.lock_upgrade();
454 bool try_lock_upgrade()
456 boost::unique_lock<boost::mutex> lk(state_change);
457 if(!state.can_lock_upgrade())
463 state.lock_upgrade();
464 state.assert_lock_upgraded();
469 void unlock_upgrade()
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)
477 state.exclusive_blocked(false);
482 shared_cond.notify_all();
486 // Upgrade <-> Exclusive
487 void unlock_upgrade_and_lock()
489 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
490 boost::this_thread::disable_interruption do_not_disturb;
492 boost::unique_lock<boost::mutex> lk(state_change);
493 state.assert_lock_upgraded();
494 // assert state.get_shared_count() >=1
496 //! state.exclusive_waiting_blocked // Fixme: is this needed?
498 state.get_shared_count()!=1)
500 upgrade_cond.wait(lk);
502 state.unlock_upgrade();
504 state.assert_locked();
507 void unlock_and_lock_upgrade()
509 boost::unique_lock<boost::mutex> lk(state_change);
510 state.assert_locked();
512 state.lock_upgrade();
513 state.assert_lock_upgraded();
517 bool try_unlock_upgrade_and_lock()
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)
526 state.unlock_upgrade();
528 state.assert_locked();
533 #ifdef BOOST_THREAD_USES_CHRONO
534 template <class Rep, class Period>
536 try_unlock_upgrade_and_lock_for(
537 const chrono::duration<Rep, Period>& rel_time)
539 return try_unlock_upgrade_and_lock_until(
540 chrono::steady_clock::now() + rel_time);
542 template <class Clock, class Duration>
544 try_unlock_upgrade_and_lock_until(
545 const chrono::time_point<Clock, Duration>& abs_time)
547 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
548 boost::this_thread::disable_interruption do_not_disturb;
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)
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)
566 if(status == cv_status::timeout)
570 state.unlock_upgrade();
576 // Shared <-> Exclusive
577 void unlock_and_lock_shared()
579 boost::unique_lock<boost::mutex> lk(state_change);
580 state.assert_locked();
586 #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
587 bool try_unlock_shared_and_lock()
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)
596 state.unlock_shared();
602 #ifdef BOOST_THREAD_USES_CHRONO
603 template <class Rep, class Period>
605 try_unlock_shared_and_lock_for(
606 const chrono::duration<Rep, Period>& rel_time)
608 return try_unlock_shared_and_lock_until(
609 chrono::steady_clock::now() + rel_time);
611 template <class Clock, class Duration>
613 try_unlock_shared_and_lock_until(
614 const chrono::time_point<Clock, Duration>& abs_time)
616 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
617 boost::this_thread::disable_interruption do_not_disturb;
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)
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?
632 && state.get_shared_count() == 1)
634 if(status == cv_status::timeout)
638 state.unlock_shared();
640 state.upgrade=false; // Is this absolutely needed?
641 state.exclusive_waiting_blocked=false; // Is this absolutely needed?
647 // Shared <-> Upgrade
648 void unlock_upgrade_and_lock_shared()
650 boost::unique_lock<boost::mutex> lk(state_change);
651 state.assert_lock_upgraded();
652 //state.unlock_upgrade();
653 //state.lock_shared(); // less efficient
655 state.exclusive_waiting_blocked=false; // Is this absolutely needed?
659 #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
660 bool try_unlock_shared_and_lock_upgrade()
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?
674 #ifdef BOOST_THREAD_USES_CHRONO
675 template <class Rep, class Period>
677 try_unlock_shared_and_lock_upgrade_for(
678 const chrono::duration<Rep, Period>& rel_time)
680 return try_unlock_shared_and_lock_upgrade_until(
681 chrono::steady_clock::now() + rel_time);
683 template <class Clock, class Duration>
685 try_unlock_shared_and_lock_upgrade_until(
686 const chrono::time_point<Clock, Duration>& abs_time)
688 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
689 boost::this_thread::disable_interruption do_not_disturb;
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?
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?
706 if(status == cv_status::timeout)
710 //state.unlock_shared();
711 //state.lock_upgrade(); // less efficient
719 typedef shared_mutex upgrade_mutex;
722 #include <boost/config/abi_suffix.hpp>