fix doc example typo
[boost.git] / boost / thread / win32 / shared_mutex.hpp
blob58e8093a8b5c14d6817aff3dd6ee27be522f976e
1 #ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
2 #define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
4 // (C) Copyright 2006-8 Anthony Williams
5 //
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>
14 #include <limits.h>
15 #include <boost/utility.hpp>
16 #include <boost/thread/thread_time.hpp>
18 #include <boost/config/abi_prefix.hpp>
20 namespace boost
22 class shared_mutex:
23 private boost::noncopyable
25 private:
26 struct state_data
28 unsigned shared_count:11,
29 shared_waiting:11,
30 exclusive:1,
31 upgrade:1,
32 exclusive_waiting:7,
33 exclusive_waiting_blocked:1;
35 friend bool operator==(state_data const& lhs,state_data const& rhs)
37 return *reinterpret_cast<unsigned const*>(&lhs)==*reinterpret_cast<unsigned const*>(&rhs);
42 template<typename T>
43 T interlocked_compare_exchange(T* target,T new_value,T comparand)
45 BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long));
46 long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast<long*>(target),
47 *reinterpret_cast<long*>(&new_value),
48 *reinterpret_cast<long*>(&comparand));
49 return *reinterpret_cast<T const*>(&res);
52 state_data state;
53 detail::win32::handle semaphores[2];
54 detail::win32::handle &unlock_sem;
55 detail::win32::handle &exclusive_sem;
56 detail::win32::handle upgrade_sem;
58 void release_waiters(state_data old_state)
60 if(old_state.exclusive_waiting)
62 BOOST_VERIFY(detail::win32::ReleaseSemaphore(exclusive_sem,1,0)!=0);
65 if(old_state.shared_waiting || old_state.exclusive_waiting)
67 BOOST_VERIFY(detail::win32::ReleaseSemaphore(unlock_sem,old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
72 public:
73 shared_mutex():
74 unlock_sem(semaphores[0]),
75 exclusive_sem(semaphores[1])
77 unlock_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
78 exclusive_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
79 upgrade_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
80 state_data state_={0};
81 state=state_;
84 ~shared_mutex()
86 detail::win32::CloseHandle(upgrade_sem);
87 detail::win32::CloseHandle(unlock_sem);
88 detail::win32::CloseHandle(exclusive_sem);
91 bool try_lock_shared()
93 state_data old_state=state;
94 for(;;)
96 state_data new_state=old_state;
97 if(!new_state.exclusive && !new_state.exclusive_waiting_blocked)
99 ++new_state.shared_count;
102 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
103 if(current_state==old_state)
105 break;
107 old_state=current_state;
109 return !(old_state.exclusive| old_state.exclusive_waiting_blocked);
112 void lock_shared()
114 BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel()));
117 template<typename TimeDuration>
118 bool timed_lock_shared(TimeDuration const & relative_time)
120 return timed_lock_shared(get_system_time()+relative_time);
123 bool timed_lock_shared(boost::system_time const& wait_until)
125 for(;;)
127 state_data old_state=state;
128 for(;;)
130 state_data new_state=old_state;
131 if(new_state.exclusive || new_state.exclusive_waiting_blocked)
133 ++new_state.shared_waiting;
135 else
137 ++new_state.shared_count;
140 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
141 if(current_state==old_state)
143 break;
145 old_state=current_state;
148 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
150 return true;
153 unsigned long const res=detail::win32::WaitForSingleObject(unlock_sem,::boost::detail::get_milliseconds_until(wait_until));
154 if(res==detail::win32::timeout)
156 for(;;)
158 state_data new_state=old_state;
159 if(new_state.exclusive || new_state.exclusive_waiting_blocked)
161 if(new_state.shared_waiting)
163 --new_state.shared_waiting;
166 else
168 ++new_state.shared_count;
171 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
172 if(current_state==old_state)
174 break;
176 old_state=current_state;
179 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
181 return true;
183 return false;
186 BOOST_ASSERT(res==0);
190 void unlock_shared()
192 state_data old_state=state;
193 for(;;)
195 state_data new_state=old_state;
196 bool const last_reader=!--new_state.shared_count;
198 if(last_reader)
200 if(new_state.upgrade)
202 new_state.upgrade=false;
203 new_state.exclusive=true;
205 else
207 if(new_state.exclusive_waiting)
209 --new_state.exclusive_waiting;
210 new_state.exclusive_waiting_blocked=false;
212 new_state.shared_waiting=0;
216 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
217 if(current_state==old_state)
219 if(last_reader)
221 if(old_state.upgrade)
223 BOOST_VERIFY(detail::win32::ReleaseSemaphore(upgrade_sem,1,0)!=0);
225 else
227 release_waiters(old_state);
230 break;
232 old_state=current_state;
236 void lock()
238 BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
241 template<typename TimeDuration>
242 bool timed_lock(TimeDuration const & relative_time)
244 return timed_lock(get_system_time()+relative_time);
247 bool try_lock()
249 state_data old_state=state;
250 for(;;)
252 state_data new_state=old_state;
253 if(new_state.shared_count || new_state.exclusive)
255 return false;
257 else
259 new_state.exclusive=true;
262 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
263 if(current_state==old_state)
265 break;
267 old_state=current_state;
269 return true;
273 bool timed_lock(boost::system_time const& wait_until)
275 for(;;)
277 state_data old_state=state;
279 for(;;)
281 state_data new_state=old_state;
282 if(new_state.shared_count || new_state.exclusive)
284 ++new_state.exclusive_waiting;
285 new_state.exclusive_waiting_blocked=true;
287 else
289 new_state.exclusive=true;
292 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
293 if(current_state==old_state)
295 break;
297 old_state=current_state;
300 if(!old_state.shared_count && !old_state.exclusive)
302 return true;
304 unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,true,::boost::detail::get_milliseconds_until(wait_until));
305 if(wait_res==detail::win32::timeout)
307 for(;;)
309 state_data new_state=old_state;
310 if(new_state.shared_count || new_state.exclusive)
312 if(new_state.exclusive_waiting)
314 if(!--new_state.exclusive_waiting)
316 new_state.exclusive_waiting_blocked=false;
320 else
322 new_state.exclusive=true;
325 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
326 if(current_state==old_state)
328 break;
330 old_state=current_state;
332 if(!old_state.shared_count && !old_state.exclusive)
334 return true;
336 return false;
338 BOOST_ASSERT(wait_res<2);
342 void unlock()
344 state_data old_state=state;
345 for(;;)
347 state_data new_state=old_state;
348 new_state.exclusive=false;
349 if(new_state.exclusive_waiting)
351 --new_state.exclusive_waiting;
352 new_state.exclusive_waiting_blocked=false;
354 new_state.shared_waiting=0;
356 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
357 if(current_state==old_state)
359 break;
361 old_state=current_state;
363 release_waiters(old_state);
366 void lock_upgrade()
368 for(;;)
370 state_data old_state=state;
371 for(;;)
373 state_data new_state=old_state;
374 if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
376 ++new_state.shared_waiting;
378 else
380 ++new_state.shared_count;
381 new_state.upgrade=true;
384 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
385 if(current_state==old_state)
387 break;
389 old_state=current_state;
392 if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade))
394 return;
397 BOOST_VERIFY(!detail::win32::WaitForSingleObject(unlock_sem,detail::win32::infinite));
401 bool try_lock_upgrade()
403 state_data old_state=state;
404 for(;;)
406 state_data new_state=old_state;
407 if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
409 return false;
411 else
413 ++new_state.shared_count;
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)
420 break;
422 old_state=current_state;
424 return true;
427 void unlock_upgrade()
429 state_data old_state=state;
430 for(;;)
432 state_data new_state=old_state;
433 new_state.upgrade=false;
434 bool const last_reader=!--new_state.shared_count;
436 if(last_reader)
438 if(new_state.exclusive_waiting)
440 --new_state.exclusive_waiting;
441 new_state.exclusive_waiting_blocked=false;
443 new_state.shared_waiting=0;
446 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
447 if(current_state==old_state)
449 if(last_reader)
451 release_waiters(old_state);
453 break;
455 old_state=current_state;
459 void unlock_upgrade_and_lock()
461 state_data old_state=state;
462 for(;;)
464 state_data new_state=old_state;
465 bool const last_reader=!--new_state.shared_count;
467 if(last_reader)
469 new_state.upgrade=false;
470 new_state.exclusive=true;
473 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
474 if(current_state==old_state)
476 if(!last_reader)
478 BOOST_VERIFY(!detail::win32::WaitForSingleObject(upgrade_sem,detail::win32::infinite));
480 break;
482 old_state=current_state;
486 void unlock_and_lock_upgrade()
488 state_data old_state=state;
489 for(;;)
491 state_data new_state=old_state;
492 new_state.exclusive=false;
493 new_state.upgrade=true;
494 ++new_state.shared_count;
495 if(new_state.exclusive_waiting)
497 --new_state.exclusive_waiting;
498 new_state.exclusive_waiting_blocked=false;
500 new_state.shared_waiting=0;
502 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
503 if(current_state==old_state)
505 break;
507 old_state=current_state;
509 release_waiters(old_state);
512 void unlock_and_lock_shared()
514 state_data old_state=state;
515 for(;;)
517 state_data new_state=old_state;
518 new_state.exclusive=false;
519 ++new_state.shared_count;
520 if(new_state.exclusive_waiting)
522 --new_state.exclusive_waiting;
523 new_state.exclusive_waiting_blocked=false;
525 new_state.shared_waiting=0;
527 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
528 if(current_state==old_state)
530 break;
532 old_state=current_state;
534 release_waiters(old_state);
537 void unlock_upgrade_and_lock_shared()
539 state_data old_state=state;
540 for(;;)
542 state_data new_state=old_state;
543 new_state.upgrade=false;
544 if(new_state.exclusive_waiting)
546 --new_state.exclusive_waiting;
547 new_state.exclusive_waiting_blocked=false;
549 new_state.shared_waiting=0;
551 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
552 if(current_state==old_state)
554 break;
556 old_state=current_state;
558 release_waiters(old_state);
564 #include <boost/config/abi_suffix.hpp>
566 #endif