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/bind.hpp>
13 #include <boost/static_assert.hpp>
14 #include <boost/thread/mutex.hpp>
15 #include <boost/thread/condition_variable.hpp>
16 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
17 #include <boost/thread/detail/thread_interruption.hpp>
19 #ifdef BOOST_THREAD_USES_CHRONO
20 #include <boost/chrono/system_clocks.hpp>
21 #include <boost/chrono/ceil.hpp>
23 #include <boost/thread/detail/delete.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);
90 exclusive_waiting_blocked = false;
93 bool can_lock_shared () const
95 return ! (exclusive || exclusive_waiting_blocked);
98 bool no_shared () const
100 return shared_count==0;
103 bool one_shared () const
105 return shared_count==1;
114 void unlock_shared ()
124 bool can_lock_upgrade () const
126 return ! (exclusive || exclusive_waiting_blocked || upgrade);
129 void unlock_upgrade ()
136 unsigned shared_count;
139 bool exclusive_waiting_blocked;
145 boost::mutex state_change;
146 boost::condition_variable shared_cond;
147 boost::condition_variable exclusive_cond;
148 boost::condition_variable upgrade_cond;
150 void release_waiters()
152 exclusive_cond.notify_one();
153 shared_cond.notify_all();
158 BOOST_THREAD_NO_COPYABLE(shared_mutex)
170 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
171 boost::this_thread::disable_interruption do_not_disturb;
173 boost::unique_lock<boost::mutex> lk(state_change);
174 shared_cond.wait(lk, boost::bind(&state_data::can_lock_shared, boost::ref(state)));
178 bool try_lock_shared()
180 boost::unique_lock<boost::mutex> lk(state_change);
182 if(!state.can_lock_shared())
190 #if defined BOOST_THREAD_USES_DATETIME
191 bool timed_lock_shared(system_time const& timeout)
193 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
194 boost::this_thread::disable_interruption do_not_disturb;
196 boost::unique_lock<boost::mutex> lk(state_change);
197 if(!shared_cond.timed_wait(lk, timeout, boost::bind(&state_data::can_lock_shared, boost::ref(state))))
205 template<typename TimeDuration>
206 bool timed_lock_shared(TimeDuration const & relative_time)
208 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
209 boost::this_thread::disable_interruption do_not_disturb;
211 boost::unique_lock<boost::mutex> lk(state_change);
212 if(!shared_cond.timed_wait(lk, relative_time, boost::bind(&state_data::can_lock_shared, boost::ref(state))))
220 #ifdef BOOST_THREAD_USES_CHRONO
221 template <class Rep, class Period>
222 bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
224 return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
226 template <class Clock, class Duration>
227 bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time)
229 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
230 boost::this_thread::disable_interruption do_not_disturb;
232 boost::unique_lock<boost::mutex> lk(state_change);
233 if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock_shared, boost::ref(state))))
243 boost::unique_lock<boost::mutex> lk(state_change);
244 state.assert_lock_shared();
245 state.unlock_shared();
246 if (state.no_shared())
250 // As there is a thread doing a unlock_upgrade_and_lock that is waiting for state.no_shared()
251 // avoid other threads to lock, lock_upgrade or lock_shared, so only this thread is notified.
253 state.exclusive=true;
255 upgrade_cond.notify_one();
259 state.exclusive_waiting_blocked=false;
268 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
269 boost::this_thread::disable_interruption do_not_disturb;
271 boost::unique_lock<boost::mutex> lk(state_change);
272 state.exclusive_waiting_blocked=true;
273 exclusive_cond.wait(lk, boost::bind(&state_data::can_lock, boost::ref(state)));
274 state.exclusive=true;
277 #if defined BOOST_THREAD_USES_DATETIME
278 bool timed_lock(system_time const& timeout)
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);
284 state.exclusive_waiting_blocked=true;
285 if(!exclusive_cond.timed_wait(lk, timeout, boost::bind(&state_data::can_lock, boost::ref(state))))
287 state.exclusive_waiting_blocked=false;
291 state.exclusive=true;
295 template<typename TimeDuration>
296 bool timed_lock(TimeDuration const & relative_time)
298 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
299 boost::this_thread::disable_interruption do_not_disturb;
301 boost::unique_lock<boost::mutex> lk(state_change);
302 state.exclusive_waiting_blocked=true;
303 if(!exclusive_cond.timed_wait(lk, relative_time, boost::bind(&state_data::can_lock, boost::ref(state))))
305 state.exclusive_waiting_blocked=false;
309 state.exclusive=true;
313 #ifdef BOOST_THREAD_USES_CHRONO
314 template <class Rep, class Period>
315 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
317 return try_lock_until(chrono::steady_clock::now() + rel_time);
319 template <class Clock, class Duration>
320 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
322 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
323 boost::this_thread::disable_interruption do_not_disturb;
325 boost::unique_lock<boost::mutex> lk(state_change);
326 state.exclusive_waiting_blocked=true;
327 if(!exclusive_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock, boost::ref(state))))
329 state.exclusive_waiting_blocked=false;
333 state.exclusive=true;
340 boost::unique_lock<boost::mutex> lk(state_change);
341 if(!state.can_lock())
345 state.exclusive=true;
351 boost::unique_lock<boost::mutex> lk(state_change);
352 state.assert_locked();
353 state.exclusive=false;
354 state.exclusive_waiting_blocked=false;
361 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
362 boost::this_thread::disable_interruption do_not_disturb;
364 boost::unique_lock<boost::mutex> lk(state_change);
365 shared_cond.wait(lk, boost::bind(&state_data::can_lock_upgrade, boost::ref(state)));
370 #if defined BOOST_THREAD_USES_DATETIME
371 bool timed_lock_upgrade(system_time const& timeout)
373 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
374 boost::this_thread::disable_interruption do_not_disturb;
376 boost::unique_lock<boost::mutex> lk(state_change);
377 if(!shared_cond.timed_wait(lk, timeout, boost::bind(&state_data::can_lock_upgrade, boost::ref(state))))
386 template<typename TimeDuration>
387 bool timed_lock_upgrade(TimeDuration const & relative_time)
389 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
390 boost::this_thread::disable_interruption do_not_disturb;
392 boost::unique_lock<boost::mutex> lk(state_change);
393 if(!shared_cond.timed_wait(lk, relative_time, boost::bind(&state_data::can_lock_upgrade, boost::ref(state))))
402 #ifdef BOOST_THREAD_USES_CHRONO
403 template <class Rep, class Period>
404 bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time)
406 return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time);
408 template <class Clock, class Duration>
409 bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time)
411 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
412 boost::this_thread::disable_interruption do_not_disturb;
414 boost::unique_lock<boost::mutex> lk(state_change);
415 if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock_upgrade, boost::ref(state))))
424 bool try_lock_upgrade()
426 boost::unique_lock<boost::mutex> lk(state_change);
427 if(!state.can_lock_upgrade())
433 state.assert_lock_upgraded();
437 void unlock_upgrade()
439 boost::unique_lock<boost::mutex> lk(state_change);
440 //state.upgrade=false;
441 state.unlock_upgrade();
442 if(state.no_shared())
444 state.exclusive_waiting_blocked=false;
447 shared_cond.notify_all();
451 // Upgrade <-> Exclusive
452 void unlock_upgrade_and_lock()
454 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
455 boost::this_thread::disable_interruption do_not_disturb;
457 boost::unique_lock<boost::mutex> lk(state_change);
458 state.assert_lock_upgraded();
459 state.unlock_shared();
460 upgrade_cond.wait(lk, boost::bind(&state_data::no_shared, boost::ref(state)));
462 state.exclusive=true;
463 state.assert_locked();
466 void unlock_and_lock_upgrade()
468 boost::unique_lock<boost::mutex> lk(state_change);
469 state.assert_locked();
470 state.exclusive=false;
473 state.exclusive_waiting_blocked=false;
474 state.assert_lock_upgraded();
478 bool try_unlock_upgrade_and_lock()
480 boost::unique_lock<boost::mutex> lk(state_change);
481 state.assert_lock_upgraded();
483 && !state.exclusive_waiting_blocked
485 && state.shared_count==1)
487 state.shared_count=0;
488 state.exclusive=true;
490 state.assert_locked();
495 #ifdef BOOST_THREAD_USES_CHRONO
496 template <class Rep, class Period>
498 try_unlock_upgrade_and_lock_for(
499 const chrono::duration<Rep, Period>& rel_time)
501 return try_unlock_upgrade_and_lock_until(
502 chrono::steady_clock::now() + rel_time);
504 template <class Clock, class Duration>
506 try_unlock_upgrade_and_lock_until(
507 const chrono::time_point<Clock, Duration>& abs_time)
509 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
510 boost::this_thread::disable_interruption do_not_disturb;
512 boost::unique_lock<boost::mutex> lk(state_change);
513 state.assert_lock_upgraded();
514 if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::one_shared, boost::ref(state))))
519 state.exclusive=true;
520 state.exclusive_waiting_blocked=false;
521 state.shared_count=0;
526 // Shared <-> Exclusive
527 void unlock_and_lock_shared()
529 boost::unique_lock<boost::mutex> lk(state_change);
530 state.assert_locked();
531 state.exclusive=false;
533 state.exclusive_waiting_blocked=false;
537 #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
538 bool try_unlock_shared_and_lock()
540 boost::unique_lock<boost::mutex> lk(state_change);
541 state.assert_lock_shared();
543 && !state.exclusive_waiting_blocked
545 && state.shared_count==1)
547 state.shared_count=0;
548 state.exclusive=true;
553 #ifdef BOOST_THREAD_USES_CHRONO
554 template <class Rep, class Period>
556 try_unlock_shared_and_lock_for(
557 const chrono::duration<Rep, Period>& rel_time)
559 return try_unlock_shared_and_lock_until(
560 chrono::steady_clock::now() + rel_time);
562 template <class Clock, class Duration>
564 try_unlock_shared_and_lock_until(
565 const chrono::time_point<Clock, Duration>& abs_time)
567 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
568 boost::this_thread::disable_interruption do_not_disturb;
570 boost::unique_lock<boost::mutex> lk(state_change);
571 state.assert_lock_shared();
572 if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::one_shared, boost::ref(state))))
577 state.exclusive=true;
578 state.exclusive_waiting_blocked=false;
579 state.shared_count=0;
585 // Shared <-> Upgrade
586 void unlock_upgrade_and_lock_shared()
588 boost::unique_lock<boost::mutex> lk(state_change);
589 state.assert_lock_upgraded();
591 state.exclusive_waiting_blocked=false;
595 #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
596 bool try_unlock_shared_and_lock_upgrade()
598 boost::unique_lock<boost::mutex> lk(state_change);
599 state.assert_lock_shared();
600 if(state.can_lock_upgrade())
607 #ifdef BOOST_THREAD_USES_CHRONO
608 template <class Rep, class Period>
610 try_unlock_shared_and_lock_upgrade_for(
611 const chrono::duration<Rep, Period>& rel_time)
613 return try_unlock_shared_and_lock_upgrade_until(
614 chrono::steady_clock::now() + rel_time);
616 template <class Clock, class Duration>
618 try_unlock_shared_and_lock_upgrade_until(
619 const chrono::time_point<Clock, Duration>& abs_time)
621 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
622 boost::this_thread::disable_interruption do_not_disturb;
624 boost::unique_lock<boost::mutex> lk(state_change);
625 state.assert_lock_shared();
626 if(!exclusive_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock_upgrade, boost::ref(state))))
637 typedef shared_mutex upgrade_mutex;
640 #include <boost/config/abi_suffix.hpp>