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,2017-2018 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>
22 #include <boost/thread/detail/platform_time.hpp>
24 #include <boost/config/abi_prefix.hpp>
33 unsigned long shared_count:11,
38 exclusive_waiting_blocked:1;
40 friend bool operator==(state_data const& lhs,state_data const& rhs)
42 return *reinterpret_cast<unsigned long const*>(&lhs)==*reinterpret_cast<unsigned long const*>(&rhs);
46 state_data interlocked_compare_exchange(state_data* target, state_data new_value, state_data comparand)
48 long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast<long*>(target),
49 *reinterpret_cast<long*>(&new_value),
50 *reinterpret_cast<long*>(&comparand));
51 return *reinterpret_cast<state_data const*>(&res);
61 detail::win32::handle semaphores[2];
62 detail::win32::handle upgrade_sem;
64 void release_waiters(state_data old_state)
66 if(old_state.exclusive_waiting)
68 BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0);
71 if(old_state.shared_waiting || old_state.exclusive_waiting)
73 BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
76 void release_shared_waiters(state_data old_state)
78 if(old_state.shared_waiting || old_state.exclusive_waiting)
80 BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
85 BOOST_THREAD_NO_COPYABLE(shared_mutex)
88 semaphores[unlock_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
89 semaphores[exclusive_sem]=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
90 if (!semaphores[exclusive_sem])
92 detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
93 boost::throw_exception(thread_resource_error());
95 upgrade_sem=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
98 detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
99 detail::win32::release_semaphore(semaphores[exclusive_sem],LONG_MAX);
100 boost::throw_exception(thread_resource_error());
102 state_data state_={0,0,0,0,0,0};
108 winapi::CloseHandle(upgrade_sem);
109 winapi::CloseHandle(semaphores[unlock_sem]);
110 winapi::CloseHandle(semaphores[exclusive_sem]);
113 bool try_lock_shared()
115 state_data old_state=state;
118 state_data new_state=old_state;
119 if(!new_state.exclusive && !new_state.exclusive_waiting_blocked)
121 ++new_state.shared_count;
122 if(!new_state.shared_count)
128 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
129 if(current_state==old_state)
133 old_state=current_state;
135 return !(old_state.exclusive| old_state.exclusive_waiting_blocked);
142 state_data old_state=state;
145 state_data new_state=old_state;
146 if(new_state.exclusive || new_state.exclusive_waiting_blocked)
148 ++new_state.shared_waiting;
149 if(!new_state.shared_waiting)
151 boost::throw_exception(boost::lock_error());
156 ++new_state.shared_count;
157 if(!new_state.shared_count)
159 boost::throw_exception(boost::lock_error());
163 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
164 if(current_state==old_state)
168 old_state=current_state;
171 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
176 BOOST_VERIFY(winapi::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::win32::infinite,0)==0);
181 unsigned long getMs(detail::platform_duration const& d)
183 return static_cast<unsigned long>(d.getMs());
186 template <typename Duration>
187 unsigned long getMs(Duration const& d)
189 return static_cast<unsigned long>(chrono::ceil<chrono::milliseconds>(d).count());
192 template <typename Clock, typename Timepoint, typename Duration>
193 bool do_lock_shared_until(Timepoint const& t, Duration const& max)
197 state_data old_state=state;
200 state_data new_state=old_state;
201 if(new_state.exclusive || new_state.exclusive_waiting_blocked)
203 ++new_state.shared_waiting;
204 if(!new_state.shared_waiting)
206 boost::throw_exception(boost::lock_error());
211 ++new_state.shared_count;
212 if(!new_state.shared_count)
214 boost::throw_exception(boost::lock_error());
218 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
219 if(current_state==old_state)
223 old_state=current_state;
226 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
231 // If the clock is the system clock, it may jump while this function
232 // is waiting. To compensate for this and time out near the correct
233 // time, we call WaitForSingleObjectEx() in a loop with a short
234 // timeout and recheck the time remaining each time through the loop.
238 Duration d(t - Clock::now());
239 if(d <= Duration::zero()) // timeout occurred
241 res=detail::win32::timeout;
244 if(max != Duration::zero())
246 d = (std::min)(d, max);
248 res=winapi::WaitForSingleObjectEx(semaphores[unlock_sem],getMs(d),0);
249 if(res!=detail::win32::timeout) // semaphore released
255 if(res==detail::win32::timeout)
259 state_data new_state=old_state;
260 if(new_state.exclusive || new_state.exclusive_waiting_blocked)
262 if(new_state.shared_waiting)
264 --new_state.shared_waiting;
269 ++new_state.shared_count;
270 if(!new_state.shared_count)
276 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
277 if(current_state==old_state)
281 old_state=current_state;
284 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
291 BOOST_ASSERT(res==0);
296 #if defined BOOST_THREAD_USES_DATETIME
297 template<typename TimeDuration>
298 bool timed_lock_shared(TimeDuration const & relative_time)
300 const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(relative_time));
301 // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
302 return do_lock_shared_until<detail::mono_platform_clock>(t, detail::platform_duration::zero());
304 bool timed_lock_shared(boost::system_time const& wait_until)
306 const detail::real_platform_timepoint t(wait_until);
307 return do_lock_shared_until<detail::real_platform_clock>(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
311 #ifdef BOOST_THREAD_USES_CHRONO
312 template <class Rep, class Period>
313 bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
315 const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time);
316 typedef typename chrono::duration<Rep, Period> Duration;
317 typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
318 // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
319 return do_lock_shared_until<chrono::steady_clock>(t, common_duration::zero());
321 template <class Duration>
322 bool try_lock_shared_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
324 typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
325 // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
326 return do_lock_shared_until<chrono::steady_clock>(t, common_duration::zero());
328 template <class Clock, class Duration>
329 bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& t)
331 typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
332 return do_lock_shared_until<Clock>(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
338 state_data old_state=state;
341 state_data new_state=old_state;
342 bool const last_reader=!--new_state.shared_count;
346 if(new_state.upgrade)
348 new_state.upgrade=false;
349 new_state.exclusive=true;
353 if(new_state.exclusive_waiting)
355 --new_state.exclusive_waiting;
356 new_state.exclusive_waiting_blocked=false;
358 new_state.shared_waiting=0;
362 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
363 if(current_state==old_state)
367 if(old_state.upgrade)
369 BOOST_VERIFY(winapi::ReleaseSemaphore(upgrade_sem,1,0)!=0);
373 release_waiters(old_state);
378 old_state=current_state;
384 state_data old_state=state;
387 state_data new_state=old_state;
388 if(new_state.shared_count || new_state.exclusive)
394 new_state.exclusive=true;
397 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
398 if(current_state==old_state)
402 old_state=current_state;
411 state_data old_state=state;
414 state_data new_state=old_state;
415 if(new_state.shared_count || new_state.exclusive)
417 ++new_state.exclusive_waiting;
418 if(!new_state.exclusive_waiting)
420 boost::throw_exception(boost::lock_error());
423 new_state.exclusive_waiting_blocked=true;
427 new_state.exclusive=true;
430 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
431 if(current_state==old_state)
435 old_state=current_state;
438 if(!old_state.shared_count && !old_state.exclusive)
444 const bool wait_all = true;
446 const bool wait_all = false;
448 BOOST_VERIFY(winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::win32::infinite,0)<2);
453 template <typename Clock, typename Timepoint, typename Duration>
454 bool do_lock_until(Timepoint const& t, Duration const& max)
458 state_data old_state=state;
461 state_data new_state=old_state;
462 if(new_state.shared_count || new_state.exclusive)
464 ++new_state.exclusive_waiting;
465 if(!new_state.exclusive_waiting)
467 boost::throw_exception(boost::lock_error());
470 new_state.exclusive_waiting_blocked=true;
474 new_state.exclusive=true;
477 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
478 if(current_state==old_state)
482 old_state=current_state;
485 if(!old_state.shared_count && !old_state.exclusive)
490 // If the clock is the system clock, it may jump while this function
491 // is waiting. To compensate for this and time out near the correct
492 // time, we call WaitForMultipleObjectsEx() in a loop with a short
493 // timeout and recheck the time remaining each time through the loop.
494 unsigned long wait_res=0;
497 Duration d(t - Clock::now());
498 if(d <= Duration::zero()) // timeout occurred
500 wait_res=detail::win32::timeout;
503 if(max != Duration::zero())
505 d = (std::min)(d, max);
508 wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,true,getMs(d),0);
510 wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,false,getMs(d),0);
512 //wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,getMs(d), 0);
514 if(wait_res!=detail::win32::timeout) // semaphore released
520 if(wait_res==detail::win32::timeout)
524 bool must_notify = false;
525 state_data new_state=old_state;
526 if(new_state.shared_count || new_state.exclusive)
528 if(new_state.exclusive_waiting)
530 if(!--new_state.exclusive_waiting)
532 new_state.exclusive_waiting_blocked=false;
539 new_state.exclusive=true;
542 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
545 BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
548 if(current_state==old_state)
552 old_state=current_state;
554 if(!old_state.shared_count && !old_state.exclusive)
561 BOOST_ASSERT(wait_res<2);
566 #if defined BOOST_THREAD_USES_DATETIME
567 bool timed_lock(boost::system_time const& wait_until)
569 const detail::real_platform_timepoint t(wait_until);
570 return do_lock_until<detail::real_platform_clock>(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
572 template<typename TimeDuration>
573 bool timed_lock(TimeDuration const & relative_time)
575 const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(relative_time));
576 // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
577 return do_lock_until<detail::mono_platform_clock>(t, detail::platform_duration::zero());
580 #ifdef BOOST_THREAD_USES_CHRONO
581 template <class Rep, class Period>
582 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
584 const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time);
585 typedef typename chrono::duration<Rep, Period> Duration;
586 typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
587 // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
588 return do_lock_until<chrono::steady_clock>(t, common_duration::zero());
590 template <class Duration>
591 bool try_lock_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
593 typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
594 // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
595 return do_lock_until<chrono::steady_clock>(t, common_duration::zero());
597 template <class Clock, class Duration>
598 bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
600 typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
601 return do_lock_until<Clock>(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
607 state_data old_state=state;
610 state_data new_state=old_state;
611 new_state.exclusive=false;
612 if(new_state.exclusive_waiting)
614 --new_state.exclusive_waiting;
615 new_state.exclusive_waiting_blocked=false;
617 new_state.shared_waiting=0;
619 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
620 if(current_state==old_state)
624 old_state=current_state;
626 release_waiters(old_state);
633 state_data old_state=state;
636 state_data new_state=old_state;
637 if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
639 ++new_state.shared_waiting;
640 if(!new_state.shared_waiting)
642 boost::throw_exception(boost::lock_error());
647 ++new_state.shared_count;
648 if(!new_state.shared_count)
650 boost::throw_exception(boost::lock_error());
652 new_state.upgrade=true;
655 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
656 if(current_state==old_state)
660 old_state=current_state;
663 if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade))
668 BOOST_VERIFY(winapi::WaitForSingleObjectEx(semaphores[unlock_sem],winapi::infinite,0)==0);
672 bool try_lock_upgrade()
674 state_data old_state=state;
677 state_data new_state=old_state;
678 if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
684 ++new_state.shared_count;
685 if(!new_state.shared_count)
689 new_state.upgrade=true;
692 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
693 if(current_state==old_state)
697 old_state=current_state;
702 void unlock_upgrade()
704 state_data old_state=state;
707 state_data new_state=old_state;
708 new_state.upgrade=false;
709 bool const last_reader=!--new_state.shared_count;
711 new_state.shared_waiting=0;
714 if(new_state.exclusive_waiting)
716 --new_state.exclusive_waiting;
717 new_state.exclusive_waiting_blocked=false;
721 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
722 if(current_state==old_state)
726 release_waiters(old_state);
729 release_shared_waiters(old_state);
733 // release_waiters(old_state);
737 old_state=current_state;
741 void unlock_upgrade_and_lock()
743 state_data old_state=state;
746 state_data new_state=old_state;
747 bool const last_reader=!--new_state.shared_count;
751 new_state.upgrade=false;
752 new_state.exclusive=true;
755 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
756 if(current_state==old_state)
760 BOOST_VERIFY(winapi::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite,0)==0);
764 old_state=current_state;
768 void unlock_and_lock_upgrade()
770 state_data old_state=state;
773 state_data new_state=old_state;
774 new_state.exclusive=false;
775 new_state.upgrade=true;
776 ++new_state.shared_count;
777 if(new_state.exclusive_waiting)
779 --new_state.exclusive_waiting;
780 new_state.exclusive_waiting_blocked=false;
782 new_state.shared_waiting=0;
784 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
785 if(current_state==old_state)
789 old_state=current_state;
791 release_waiters(old_state);
794 void unlock_and_lock_shared()
796 state_data old_state=state;
799 state_data new_state=old_state;
800 new_state.exclusive=false;
801 ++new_state.shared_count;
802 if(new_state.exclusive_waiting)
804 --new_state.exclusive_waiting;
805 new_state.exclusive_waiting_blocked=false;
807 new_state.shared_waiting=0;
809 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
810 if(current_state==old_state)
814 old_state=current_state;
816 release_waiters(old_state);
818 void unlock_upgrade_and_lock_shared()
820 state_data old_state=state;
823 state_data new_state=old_state;
824 new_state.upgrade=false;
825 if(new_state.exclusive_waiting)
827 --new_state.exclusive_waiting;
828 new_state.exclusive_waiting_blocked=false;
830 new_state.shared_waiting=0;
832 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
833 if(current_state==old_state)
837 old_state=current_state;
839 release_waiters(old_state);
843 typedef shared_mutex upgrade_mutex;
847 #include <boost/config/abi_suffix.hpp>