1 #ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
2 #define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
4 // (C) Copyright 2006-8 Anthony Williams
5 // (C) Copyright 2011-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/detail/interlocked.hpp>
13 #include <boost/thread/win32/thread_primitives.hpp>
14 #include <boost/static_assert.hpp>
16 #include <boost/thread/thread_time.hpp>
17 #ifdef BOOST_THREAD_USES_CHRONO
18 #include <boost/chrono/system_clocks.hpp>
19 #include <boost/chrono/ceil.hpp>
21 #include <boost/thread/detail/delete.hpp>
23 #include <boost/config/abi_prefix.hpp>
32 unsigned shared_count:11,
37 exclusive_waiting_blocked:1;
39 friend bool operator==(state_data const& lhs,state_data const& rhs)
41 return *reinterpret_cast<unsigned const*>(&lhs)==*reinterpret_cast<unsigned const*>(&rhs);
47 T interlocked_compare_exchange(T* target,T new_value,T comparand)
49 BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long));
50 long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast<long*>(target),
51 *reinterpret_cast<long*>(&new_value),
52 *reinterpret_cast<long*>(&comparand));
53 return *reinterpret_cast<T const*>(&res);
63 detail::win32::handle semaphores[2];
64 detail::win32::handle upgrade_sem;
66 void release_waiters(state_data old_state)
68 if(old_state.exclusive_waiting)
70 BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0);
73 if(old_state.shared_waiting || old_state.exclusive_waiting)
75 BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
78 void release_shared_waiters(state_data old_state)
80 if(old_state.shared_waiting || old_state.exclusive_waiting)
82 BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
87 BOOST_THREAD_NO_COPYABLE(shared_mutex)
90 semaphores[unlock_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
91 semaphores[exclusive_sem]=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
92 if (!semaphores[exclusive_sem])
94 detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
95 boost::throw_exception(thread_resource_error());
97 upgrade_sem=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
100 detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
101 detail::win32::release_semaphore(semaphores[exclusive_sem],LONG_MAX);
102 boost::throw_exception(thread_resource_error());
104 state_data state_={0,0,0,0,0,0};
110 detail::win32::CloseHandle(upgrade_sem);
111 detail::win32::CloseHandle(semaphores[unlock_sem]);
112 detail::win32::CloseHandle(semaphores[exclusive_sem]);
115 bool try_lock_shared()
117 state_data old_state=state;
120 state_data new_state=old_state;
121 if(!new_state.exclusive && !new_state.exclusive_waiting_blocked)
123 ++new_state.shared_count;
124 if(!new_state.shared_count)
130 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
131 if(current_state==old_state)
135 old_state=current_state;
137 return !(old_state.exclusive| old_state.exclusive_waiting_blocked);
143 #if defined BOOST_THREAD_USES_DATETIME
144 BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel()));
146 BOOST_VERIFY(try_lock_shared_until(chrono::steady_clock::now()));
150 #if defined BOOST_THREAD_USES_DATETIME
151 template<typename TimeDuration>
152 bool timed_lock_shared(TimeDuration const & relative_time)
154 return timed_lock_shared(get_system_time()+relative_time);
156 bool timed_lock_shared(boost::system_time const& wait_until)
160 state_data old_state=state;
163 state_data new_state=old_state;
164 if(new_state.exclusive || new_state.exclusive_waiting_blocked)
166 ++new_state.shared_waiting;
167 if(!new_state.shared_waiting)
169 boost::throw_exception(boost::lock_error());
174 ++new_state.shared_count;
175 if(!new_state.shared_count)
177 boost::throw_exception(boost::lock_error());
181 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
182 if(current_state==old_state)
186 old_state=current_state;
189 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
194 unsigned long const res=detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until), 0);
195 if(res==detail::win32::timeout)
199 state_data new_state=old_state;
200 if(new_state.exclusive || new_state.exclusive_waiting_blocked)
202 if(new_state.shared_waiting)
204 --new_state.shared_waiting;
209 ++new_state.shared_count;
210 if(!new_state.shared_count)
216 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
217 if(current_state==old_state)
221 old_state=current_state;
224 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
231 BOOST_ASSERT(res==0);
236 #ifdef BOOST_THREAD_USES_CHRONO
237 template <class Rep, class Period>
238 bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
240 return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
242 template <class Clock, class Duration>
243 bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& t)
245 using namespace chrono;
246 system_clock::time_point s_now = system_clock::now();
247 typename Clock::time_point c_now = Clock::now();
248 return try_lock_shared_until(s_now + ceil<system_clock::duration>(t - c_now));
250 template <class Duration>
251 bool try_lock_shared_until(const chrono::time_point<chrono::system_clock, Duration>& t)
253 using namespace chrono;
254 typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt;
255 return try_lock_shared_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch())));
257 bool try_lock_shared_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp)
261 state_data old_state=state;
264 state_data new_state=old_state;
265 if(new_state.exclusive || new_state.exclusive_waiting_blocked)
267 ++new_state.shared_waiting;
268 if(!new_state.shared_waiting)
270 boost::throw_exception(boost::lock_error());
275 ++new_state.shared_count;
276 if(!new_state.shared_count)
278 boost::throw_exception(boost::lock_error());
282 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
283 if(current_state==old_state)
287 old_state=current_state;
290 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
295 chrono::system_clock::time_point n = chrono::system_clock::now();
298 chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-n);
299 res=detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],
300 static_cast<unsigned long>(rel_time.count()), 0);
302 res=detail::win32::timeout;
304 if(res==detail::win32::timeout)
308 state_data new_state=old_state;
309 if(new_state.exclusive || new_state.exclusive_waiting_blocked)
311 if(new_state.shared_waiting)
313 --new_state.shared_waiting;
318 ++new_state.shared_count;
319 if(!new_state.shared_count)
325 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
326 if(current_state==old_state)
330 old_state=current_state;
333 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
340 BOOST_ASSERT(res==0);
347 state_data old_state=state;
350 state_data new_state=old_state;
351 bool const last_reader=!--new_state.shared_count;
355 if(new_state.upgrade)
357 new_state.upgrade=false;
358 new_state.exclusive=true;
362 if(new_state.exclusive_waiting)
364 --new_state.exclusive_waiting;
365 new_state.exclusive_waiting_blocked=false;
367 new_state.shared_waiting=0;
371 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
372 if(current_state==old_state)
376 if(old_state.upgrade)
378 BOOST_VERIFY(detail::win32::ReleaseSemaphore(upgrade_sem,1,0)!=0);
382 release_waiters(old_state);
387 old_state=current_state;
394 #if defined BOOST_THREAD_USES_DATETIME
395 BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
397 BOOST_VERIFY(try_lock_until(chrono::steady_clock::now()));
401 #if defined BOOST_THREAD_USES_DATETIME
402 template<typename TimeDuration>
403 bool timed_lock(TimeDuration const & relative_time)
405 return timed_lock(get_system_time()+relative_time);
411 state_data old_state=state;
414 state_data new_state=old_state;
415 if(new_state.shared_count || new_state.exclusive)
421 new_state.exclusive=true;
424 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
425 if(current_state==old_state)
429 old_state=current_state;
435 #if defined BOOST_THREAD_USES_DATETIME
436 bool timed_lock(boost::system_time const& wait_until)
440 state_data old_state=state;
444 state_data new_state=old_state;
445 if(new_state.shared_count || new_state.exclusive)
447 ++new_state.exclusive_waiting;
448 if(!new_state.exclusive_waiting)
450 boost::throw_exception(boost::lock_error());
453 new_state.exclusive_waiting_blocked=true;
457 new_state.exclusive=true;
460 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
461 if(current_state==old_state)
465 old_state=current_state;
468 if(!old_state.shared_count && !old_state.exclusive)
473 const bool wait_all = true;
475 const bool wait_all = false;
477 unsigned long const wait_res=detail::win32::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until), 0);
478 if(wait_res==detail::win32::timeout)
482 bool must_notify = false;
483 state_data new_state=old_state;
484 if(new_state.shared_count || new_state.exclusive)
486 if(new_state.exclusive_waiting)
488 if(!--new_state.exclusive_waiting)
490 new_state.exclusive_waiting_blocked=false;
497 new_state.exclusive=true;
500 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
503 BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
506 if(current_state==old_state)
510 old_state=current_state;
512 if(!old_state.shared_count && !old_state.exclusive)
518 BOOST_ASSERT(wait_res<2);
522 #ifdef BOOST_THREAD_USES_CHRONO
523 template <class Rep, class Period>
524 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
526 return try_lock_until(chrono::steady_clock::now() + rel_time);
528 template <class Clock, class Duration>
529 bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
531 using namespace chrono;
532 system_clock::time_point s_now = system_clock::now();
533 typename Clock::time_point c_now = Clock::now();
534 return try_lock_until(s_now + ceil<system_clock::duration>(t - c_now));
536 template <class Duration>
537 bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
539 using namespace chrono;
540 typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt;
541 return try_lock_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch())));
543 bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp)
547 state_data old_state=state;
551 state_data new_state=old_state;
552 if(new_state.shared_count || new_state.exclusive)
554 ++new_state.exclusive_waiting;
555 if(!new_state.exclusive_waiting)
557 boost::throw_exception(boost::lock_error());
560 new_state.exclusive_waiting_blocked=true;
564 new_state.exclusive=true;
567 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
568 if(current_state==old_state)
572 old_state=current_state;
575 if(!old_state.shared_count && !old_state.exclusive)
580 const bool wait_all = true;
582 const bool wait_all = false;
585 chrono::system_clock::time_point n = chrono::system_clock::now();
586 unsigned long wait_res;
588 chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
589 wait_res=detail::win32::WaitForMultipleObjectsEx(2,semaphores,wait_all,
590 static_cast<unsigned long>(rel_time.count()), 0);
592 wait_res=detail::win32::timeout;
594 if(wait_res==detail::win32::timeout)
598 bool must_notify = false;
599 state_data new_state=old_state;
600 if(new_state.shared_count || new_state.exclusive)
602 if(new_state.exclusive_waiting)
604 if(!--new_state.exclusive_waiting)
606 new_state.exclusive_waiting_blocked=false;
613 new_state.exclusive=true;
616 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
619 BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
621 if(current_state==old_state)
625 old_state=current_state;
627 if(!old_state.shared_count && !old_state.exclusive)
633 BOOST_ASSERT(wait_res<2);
640 state_data old_state=state;
643 state_data new_state=old_state;
644 new_state.exclusive=false;
645 if(new_state.exclusive_waiting)
647 --new_state.exclusive_waiting;
648 new_state.exclusive_waiting_blocked=false;
650 new_state.shared_waiting=0;
652 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
653 if(current_state==old_state)
657 old_state=current_state;
659 release_waiters(old_state);
666 state_data old_state=state;
669 state_data new_state=old_state;
670 if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
672 ++new_state.shared_waiting;
673 if(!new_state.shared_waiting)
675 boost::throw_exception(boost::lock_error());
680 ++new_state.shared_count;
681 if(!new_state.shared_count)
683 boost::throw_exception(boost::lock_error());
685 new_state.upgrade=true;
688 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
689 if(current_state==old_state)
693 old_state=current_state;
696 if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade))
701 BOOST_VERIFY(!detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],detail::win32::infinite, 0));
705 bool try_lock_upgrade()
707 state_data old_state=state;
710 state_data new_state=old_state;
711 if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
717 ++new_state.shared_count;
718 if(!new_state.shared_count)
722 new_state.upgrade=true;
725 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
726 if(current_state==old_state)
730 old_state=current_state;
735 void unlock_upgrade()
737 state_data old_state=state;
740 state_data new_state=old_state;
741 new_state.upgrade=false;
742 bool const last_reader=!--new_state.shared_count;
744 new_state.shared_waiting=0;
747 if(new_state.exclusive_waiting)
749 --new_state.exclusive_waiting;
750 new_state.exclusive_waiting_blocked=false;
754 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
755 if(current_state==old_state)
759 release_waiters(old_state);
762 release_shared_waiters(old_state);
766 // release_waiters(old_state);
770 old_state=current_state;
774 void unlock_upgrade_and_lock()
776 state_data old_state=state;
779 state_data new_state=old_state;
780 bool const last_reader=!--new_state.shared_count;
784 new_state.upgrade=false;
785 new_state.exclusive=true;
788 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
789 if(current_state==old_state)
793 BOOST_VERIFY(!detail::win32::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite, 0));
797 old_state=current_state;
801 void unlock_and_lock_upgrade()
803 state_data old_state=state;
806 state_data new_state=old_state;
807 new_state.exclusive=false;
808 new_state.upgrade=true;
809 ++new_state.shared_count;
810 if(new_state.exclusive_waiting)
812 --new_state.exclusive_waiting;
813 new_state.exclusive_waiting_blocked=false;
815 new_state.shared_waiting=0;
817 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
818 if(current_state==old_state)
822 old_state=current_state;
824 release_waiters(old_state);
826 // bool try_unlock_upgrade_and_lock()
830 //#ifdef BOOST_THREAD_USES_CHRONO
831 // template <class Rep, class Period>
833 // try_unlock_upgrade_and_lock_for(
834 // const chrono::duration<Rep, Period>& rel_time)
836 // return try_unlock_upgrade_and_lock_until(
837 // chrono::steady_clock::now() + rel_time);
839 // template <class Clock, class Duration>
841 // try_unlock_upgrade_and_lock_until(
842 // const chrono::time_point<Clock, Duration>& abs_time)
848 void unlock_and_lock_shared()
850 state_data old_state=state;
853 state_data new_state=old_state;
854 new_state.exclusive=false;
855 ++new_state.shared_count;
856 if(new_state.exclusive_waiting)
858 --new_state.exclusive_waiting;
859 new_state.exclusive_waiting_blocked=false;
861 new_state.shared_waiting=0;
863 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
864 if(current_state==old_state)
868 old_state=current_state;
870 release_waiters(old_state);
872 void unlock_upgrade_and_lock_shared()
874 state_data old_state=state;
877 state_data new_state=old_state;
878 new_state.upgrade=false;
879 if(new_state.exclusive_waiting)
881 --new_state.exclusive_waiting;
882 new_state.exclusive_waiting_blocked=false;
884 new_state.shared_waiting=0;
886 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
887 if(current_state==old_state)
891 old_state=current_state;
893 release_waiters(old_state);
897 typedef shared_mutex upgrade_mutex;
901 #include <boost/config/abi_suffix.hpp>