1 #ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
2 #define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
4 // (C) Copyright 2006-8 Anthony Williams
6 // Distributed under the Boost Software License, Version 1.0. (See
7 // accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
10 #include <boost/assert.hpp>
11 #include <boost/detail/interlocked.hpp>
12 #include <boost/thread/win32/thread_primitives.hpp>
13 #include <boost/static_assert.hpp>
15 #include <boost/utility.hpp>
16 #include <boost/thread/thread_time.hpp>
18 #include <boost/config/abi_prefix.hpp>
25 shared_mutex(shared_mutex const&);
26 shared_mutex& operator=(shared_mutex const&);
30 unsigned shared_count:11,
35 exclusive_waiting_blocked:1;
37 friend bool operator==(state_data const& lhs,state_data const& rhs)
39 return *reinterpret_cast<unsigned const*>(&lhs)==*reinterpret_cast<unsigned const*>(&rhs);
45 T interlocked_compare_exchange(T* target,T new_value,T comparand)
47 BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long));
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<T 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(detail::win32::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0);
71 if(old_state.shared_waiting || old_state.exclusive_waiting)
73 BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
81 semaphores[unlock_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
82 semaphores[exclusive_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
83 upgrade_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
84 state_data state_={0};
90 detail::win32::CloseHandle(upgrade_sem);
91 detail::win32::CloseHandle(semaphores[unlock_sem]);
92 detail::win32::CloseHandle(semaphores[exclusive_sem]);
95 bool try_lock_shared()
97 state_data old_state=state;
100 state_data new_state=old_state;
101 if(!new_state.exclusive && !new_state.exclusive_waiting_blocked)
103 ++new_state.shared_count;
104 if(!new_state.shared_count)
110 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
111 if(current_state==old_state)
115 old_state=current_state;
117 return !(old_state.exclusive| old_state.exclusive_waiting_blocked);
122 BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel()));
125 template<typename TimeDuration>
126 bool timed_lock_shared(TimeDuration const & relative_time)
128 return timed_lock_shared(get_system_time()+relative_time);
131 bool timed_lock_shared(boost::system_time const& wait_until)
135 state_data old_state=state;
138 state_data new_state=old_state;
139 if(new_state.exclusive || new_state.exclusive_waiting_blocked)
141 ++new_state.shared_waiting;
142 if(!new_state.shared_waiting)
144 boost::throw_exception(boost::lock_error());
149 ++new_state.shared_count;
150 if(!new_state.shared_count)
152 boost::throw_exception(boost::lock_error());
156 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
157 if(current_state==old_state)
161 old_state=current_state;
164 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
169 unsigned long const res=detail::win32::WaitForSingleObject(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until));
170 if(res==detail::win32::timeout)
174 state_data new_state=old_state;
175 if(new_state.exclusive || new_state.exclusive_waiting_blocked)
177 if(new_state.shared_waiting)
179 --new_state.shared_waiting;
184 ++new_state.shared_count;
185 if(!new_state.shared_count)
191 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
192 if(current_state==old_state)
196 old_state=current_state;
199 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
206 BOOST_ASSERT(res==0);
212 state_data old_state=state;
215 state_data new_state=old_state;
216 bool const last_reader=!--new_state.shared_count;
220 if(new_state.upgrade)
222 new_state.upgrade=false;
223 new_state.exclusive=true;
227 if(new_state.exclusive_waiting)
229 --new_state.exclusive_waiting;
230 new_state.exclusive_waiting_blocked=false;
232 new_state.shared_waiting=0;
236 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
237 if(current_state==old_state)
241 if(old_state.upgrade)
243 BOOST_VERIFY(detail::win32::ReleaseSemaphore(upgrade_sem,1,0)!=0);
247 release_waiters(old_state);
252 old_state=current_state;
258 BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
261 template<typename TimeDuration>
262 bool timed_lock(TimeDuration const & relative_time)
264 return timed_lock(get_system_time()+relative_time);
269 state_data old_state=state;
272 state_data new_state=old_state;
273 if(new_state.shared_count || new_state.exclusive)
279 new_state.exclusive=true;
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;
293 bool timed_lock(boost::system_time const& wait_until)
297 state_data old_state=state;
301 state_data new_state=old_state;
302 if(new_state.shared_count || new_state.exclusive)
304 ++new_state.exclusive_waiting;
305 if(!new_state.exclusive_waiting)
307 boost::throw_exception(boost::lock_error());
310 new_state.exclusive_waiting_blocked=true;
314 new_state.exclusive=true;
317 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
318 if(current_state==old_state)
322 old_state=current_state;
325 if(!old_state.shared_count && !old_state.exclusive)
329 unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,true,::boost::detail::get_milliseconds_until(wait_until));
330 if(wait_res==detail::win32::timeout)
334 state_data new_state=old_state;
335 if(new_state.shared_count || new_state.exclusive)
337 if(new_state.exclusive_waiting)
339 if(!--new_state.exclusive_waiting)
341 new_state.exclusive_waiting_blocked=false;
347 new_state.exclusive=true;
350 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
351 if(current_state==old_state)
355 old_state=current_state;
357 if(!old_state.shared_count && !old_state.exclusive)
363 BOOST_ASSERT(wait_res<2);
369 state_data old_state=state;
372 state_data new_state=old_state;
373 new_state.exclusive=false;
374 if(new_state.exclusive_waiting)
376 --new_state.exclusive_waiting;
377 new_state.exclusive_waiting_blocked=false;
379 new_state.shared_waiting=0;
381 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
382 if(current_state==old_state)
386 old_state=current_state;
388 release_waiters(old_state);
395 state_data old_state=state;
398 state_data new_state=old_state;
399 if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
401 ++new_state.shared_waiting;
402 if(!new_state.shared_waiting)
404 boost::throw_exception(boost::lock_error());
409 ++new_state.shared_count;
410 if(!new_state.shared_count)
412 boost::throw_exception(boost::lock_error());
414 new_state.upgrade=true;
417 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
418 if(current_state==old_state)
422 old_state=current_state;
425 if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade))
430 BOOST_VERIFY(!detail::win32::WaitForSingleObject(semaphores[unlock_sem],detail::win32::infinite));
434 bool try_lock_upgrade()
436 state_data old_state=state;
439 state_data new_state=old_state;
440 if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
446 ++new_state.shared_count;
447 if(!new_state.shared_count)
451 new_state.upgrade=true;
454 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
455 if(current_state==old_state)
459 old_state=current_state;
464 void unlock_upgrade()
466 state_data old_state=state;
469 state_data new_state=old_state;
470 new_state.upgrade=false;
471 bool const last_reader=!--new_state.shared_count;
475 if(new_state.exclusive_waiting)
477 --new_state.exclusive_waiting;
478 new_state.exclusive_waiting_blocked=false;
480 new_state.shared_waiting=0;
483 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
484 if(current_state==old_state)
488 release_waiters(old_state);
492 old_state=current_state;
496 void unlock_upgrade_and_lock()
498 state_data old_state=state;
501 state_data new_state=old_state;
502 bool const last_reader=!--new_state.shared_count;
506 new_state.upgrade=false;
507 new_state.exclusive=true;
510 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
511 if(current_state==old_state)
515 BOOST_VERIFY(!detail::win32::WaitForSingleObject(upgrade_sem,detail::win32::infinite));
519 old_state=current_state;
523 void unlock_and_lock_upgrade()
525 state_data old_state=state;
528 state_data new_state=old_state;
529 new_state.exclusive=false;
530 new_state.upgrade=true;
531 ++new_state.shared_count;
532 if(new_state.exclusive_waiting)
534 --new_state.exclusive_waiting;
535 new_state.exclusive_waiting_blocked=false;
537 new_state.shared_waiting=0;
539 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
540 if(current_state==old_state)
544 old_state=current_state;
546 release_waiters(old_state);
549 void unlock_and_lock_shared()
551 state_data old_state=state;
554 state_data new_state=old_state;
555 new_state.exclusive=false;
556 ++new_state.shared_count;
557 if(new_state.exclusive_waiting)
559 --new_state.exclusive_waiting;
560 new_state.exclusive_waiting_blocked=false;
562 new_state.shared_waiting=0;
564 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
565 if(current_state==old_state)
569 old_state=current_state;
571 release_waiters(old_state);
574 void unlock_upgrade_and_lock_shared()
576 state_data old_state=state;
579 state_data new_state=old_state;
580 new_state.upgrade=false;
581 if(new_state.exclusive_waiting)
583 --new_state.exclusive_waiting;
584 new_state.exclusive_waiting_blocked=false;
586 new_state.shared_waiting=0;
588 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
589 if(current_state==old_state)
593 old_state=current_state;
595 release_waiters(old_state);
601 #include <boost/config/abi_suffix.hpp>