Ticket #7720: shared_mutex.hpp

File shared_mutex.hpp, 31.0 KB (added by Hung Mai <duchungjava@…>, 7 years ago)

Starting from 1.57, unlock_upgrade() should always reset the variable "new_state.shared_waiting"

Line 
1#ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
2#define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
3
4// (C) Copyright 2006-8 Anthony Williams
5// (C) Copyright 2011-2012 Vicente J. Botet Escriba
6//
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)
10
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>
15#include <limits.h>
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>
20#endif
21#include <boost/thread/detail/delete.hpp>
22
23#include <boost/config/abi_prefix.hpp>
24
25namespace boost
26{
27 class shared_mutex
28 {
29 private:
30 struct state_data
31 {
32 unsigned shared_count:11,
33 shared_waiting:11,
34 exclusive:1,
35 upgrade:1,
36 exclusive_waiting:7,
37 exclusive_waiting_blocked:1;
38
39 friend bool operator==(state_data const& lhs,state_data const& rhs)
40 {
41 return *reinterpret_cast<unsigned const*>(&lhs)==*reinterpret_cast<unsigned const*>(&rhs);
42 }
43 };
44
45
46 template<typename T>
47 T interlocked_compare_exchange(T* target,T new_value,T comparand)
48 {
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);
54 }
55
56 enum
57 {
58 unlock_sem = 0,
59 exclusive_sem = 1
60 };
61
62 state_data state;
63 detail::win32::handle semaphores[2];
64 detail::win32::handle upgrade_sem;
65
66 void release_waiters(state_data old_state)
67 {
68 if(old_state.exclusive_waiting)
69 {
70 BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0);
71 }
72
73 if(old_state.shared_waiting || old_state.exclusive_waiting)
74 {
75 BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
76 }
77 }
78 void release_shared_waiters(state_data old_state)
79 {
80 if(old_state.shared_waiting || old_state.exclusive_waiting)
81 {
82 BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
83 }
84 }
85
86 public:
87 BOOST_THREAD_NO_COPYABLE(shared_mutex)
88 shared_mutex()
89 {
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])
93 {
94 detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
95 boost::throw_exception(thread_resource_error());
96 }
97 upgrade_sem=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
98 if (!upgrade_sem)
99 {
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());
103 }
104 state_data state_={0,0,0,0,0,0};
105 state=state_;
106 }
107
108 ~shared_mutex()
109 {
110 detail::win32::CloseHandle(upgrade_sem);
111 detail::win32::CloseHandle(semaphores[unlock_sem]);
112 detail::win32::CloseHandle(semaphores[exclusive_sem]);
113 }
114
115 bool try_lock_shared()
116 {
117 state_data old_state=state;
118 for(;;)
119 {
120 state_data new_state=old_state;
121 if(!new_state.exclusive && !new_state.exclusive_waiting_blocked)
122 {
123 ++new_state.shared_count;
124 if(!new_state.shared_count)
125 {
126 return false;
127 }
128 }
129
130 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
131 if(current_state==old_state)
132 {
133 break;
134 }
135 old_state=current_state;
136 }
137 return !(old_state.exclusive| old_state.exclusive_waiting_blocked);
138 }
139
140 void lock_shared()
141 {
142#if defined BOOST_THREAD_USES_DATETIME
143 BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel()));
144#else
145 BOOST_VERIFY(try_lock_shared_until(chrono::steady_clock::now()));
146#endif
147 }
148
149#if defined BOOST_THREAD_USES_DATETIME
150 template<typename TimeDuration>
151 bool timed_lock_shared(TimeDuration const & relative_time)
152 {
153 return timed_lock_shared(get_system_time()+relative_time);
154 }
155 bool timed_lock_shared(boost::system_time const& wait_until)
156 {
157 for(;;)
158 {
159 state_data old_state=state;
160 for(;;)
161 {
162 state_data new_state=old_state;
163 if(new_state.exclusive || new_state.exclusive_waiting_blocked)
164 {
165 ++new_state.shared_waiting;
166 if(!new_state.shared_waiting)
167 {
168 boost::throw_exception(boost::lock_error());
169 }
170 }
171 else
172 {
173 ++new_state.shared_count;
174 if(!new_state.shared_count)
175 {
176 boost::throw_exception(boost::lock_error());
177 }
178 }
179
180 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
181 if(current_state==old_state)
182 {
183 break;
184 }
185 old_state=current_state;
186 }
187
188 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
189 {
190 return true;
191 }
192
193 unsigned long const res=detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until), 0);
194 if(res==detail::win32::timeout)
195 {
196 for(;;)
197 {
198 state_data new_state=old_state;
199 if(new_state.exclusive || new_state.exclusive_waiting_blocked)
200 {
201 if(new_state.shared_waiting)
202 {
203 --new_state.shared_waiting;
204 }
205 }
206 else
207 {
208 ++new_state.shared_count;
209 if(!new_state.shared_count)
210 {
211 return false;
212 }
213 }
214
215 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
216 if(current_state==old_state)
217 {
218 break;
219 }
220 old_state=current_state;
221 }
222
223 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
224 {
225 return true;
226 }
227 return false;
228 }
229
230 BOOST_ASSERT(res==0);
231 }
232 }
233#endif
234
235#ifdef BOOST_THREAD_USES_CHRONO
236 template <class Rep, class Period>
237 bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
238 {
239 return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
240 }
241 template <class Clock, class Duration>
242 bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& t)
243 {
244 using namespace chrono;
245 system_clock::time_point s_now = system_clock::now();
246 typename Clock::time_point c_now = Clock::now();
247 return try_lock_shared_until(s_now + ceil<system_clock::duration>(t - c_now));
248 }
249 template <class Duration>
250 bool try_lock_shared_until(const chrono::time_point<chrono::system_clock, Duration>& t)
251 {
252 using namespace chrono;
253 typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt;
254 return try_lock_shared_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch())));
255 }
256 bool try_lock_shared_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp)
257 {
258 for(;;)
259 {
260 state_data old_state=state;
261 for(;;)
262 {
263 state_data new_state=old_state;
264 if(new_state.exclusive || new_state.exclusive_waiting_blocked)
265 {
266 ++new_state.shared_waiting;
267 if(!new_state.shared_waiting)
268 {
269 boost::throw_exception(boost::lock_error());
270 }
271 }
272 else
273 {
274 ++new_state.shared_count;
275 if(!new_state.shared_count)
276 {
277 boost::throw_exception(boost::lock_error());
278 }
279 }
280
281 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
282 if(current_state==old_state)
283 {
284 break;
285 }
286 old_state=current_state;
287 }
288
289 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
290 {
291 return true;
292 }
293
294 chrono::system_clock::time_point n = chrono::system_clock::now();
295 unsigned long res;
296 if (tp>n) {
297 chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-n);
298 res=detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],
299 static_cast<unsigned long>(rel_time.count()), 0);
300 } else {
301 res=detail::win32::timeout;
302 }
303 if(res==detail::win32::timeout)
304 {
305 for(;;)
306 {
307 state_data new_state=old_state;
308 if(new_state.exclusive || new_state.exclusive_waiting_blocked)
309 {
310 if(new_state.shared_waiting)
311 {
312 --new_state.shared_waiting;
313 }
314 }
315 else
316 {
317 ++new_state.shared_count;
318 if(!new_state.shared_count)
319 {
320 return false;
321 }
322 }
323
324 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
325 if(current_state==old_state)
326 {
327 break;
328 }
329 old_state=current_state;
330 }
331
332 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
333 {
334 return true;
335 }
336 return false;
337 }
338
339 BOOST_ASSERT(res==0);
340 }
341 }
342#endif
343
344 void unlock_shared()
345 {
346 state_data old_state=state;
347 for(;;)
348 {
349 state_data new_state=old_state;
350 bool const last_reader=!--new_state.shared_count;
351
352 if(last_reader)
353 {
354 if(new_state.upgrade)
355 {
356 new_state.upgrade=false;
357 new_state.exclusive=true;
358 }
359 else
360 {
361 if(new_state.exclusive_waiting)
362 {
363 --new_state.exclusive_waiting;
364 new_state.exclusive_waiting_blocked=false;
365 }
366 new_state.shared_waiting=0;
367 }
368 }
369
370 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
371 if(current_state==old_state)
372 {
373 if(last_reader)
374 {
375 if(old_state.upgrade)
376 {
377 BOOST_VERIFY(detail::win32::ReleaseSemaphore(upgrade_sem,1,0)!=0);
378 }
379 else
380 {
381 release_waiters(old_state);
382 }
383 }
384 break;
385 }
386 old_state=current_state;
387 }
388 }
389
390 void lock()
391 {
392#if defined BOOST_THREAD_USES_DATETIME
393 BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
394#else
395 BOOST_VERIFY(try_lock_until(chrono::steady_clock::now()));
396#endif
397 }
398
399#if defined BOOST_THREAD_USES_DATETIME
400 template<typename TimeDuration>
401 bool timed_lock(TimeDuration const & relative_time)
402 {
403 return timed_lock(get_system_time()+relative_time);
404 }
405#endif
406
407 bool try_lock()
408 {
409 state_data old_state=state;
410 for(;;)
411 {
412 state_data new_state=old_state;
413 if(new_state.shared_count || new_state.exclusive)
414 {
415 return false;
416 }
417 else
418 {
419 new_state.exclusive=true;
420 }
421
422 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
423 if(current_state==old_state)
424 {
425 break;
426 }
427 old_state=current_state;
428 }
429 return true;
430 }
431
432
433#if defined BOOST_THREAD_USES_DATETIME
434 bool timed_lock(boost::system_time const& wait_until)
435 {
436 for(;;)
437 {
438 state_data old_state=state;
439
440 for(;;)
441 {
442 state_data new_state=old_state;
443 if(new_state.shared_count || new_state.exclusive)
444 {
445 ++new_state.exclusive_waiting;
446 if(!new_state.exclusive_waiting)
447 {
448 boost::throw_exception(boost::lock_error());
449 }
450
451 new_state.exclusive_waiting_blocked=true;
452 }
453 else
454 {
455 new_state.exclusive=true;
456 }
457
458 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
459 if(current_state==old_state)
460 {
461 break;
462 }
463 old_state=current_state;
464 }
465
466 if(!old_state.shared_count && !old_state.exclusive)
467 {
468 return true;
469 }
470 #ifndef UNDER_CE
471 const bool wait_all = true;
472 #else
473 const bool wait_all = false;
474 #endif
475 unsigned long const wait_res=detail::win32::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until), 0);
476 if(wait_res==detail::win32::timeout)
477 {
478 for(;;)
479 {
480 bool must_notify = false;
481 state_data new_state=old_state;
482 if(new_state.shared_count || new_state.exclusive)
483 {
484 if(new_state.exclusive_waiting)
485 {
486 if(!--new_state.exclusive_waiting)
487 {
488 new_state.exclusive_waiting_blocked=false;
489 must_notify = true;
490 }
491 }
492 }
493 else
494 {
495 new_state.exclusive=true;
496 }
497
498 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
499 if (must_notify)
500 {
501 BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
502 }
503
504 if(current_state==old_state)
505 {
506 break;
507 }
508 old_state=current_state;
509 }
510 if(!old_state.shared_count && !old_state.exclusive)
511 {
512 return true;
513 }
514 return false;
515 }
516 BOOST_ASSERT(wait_res<2);
517 }
518 }
519#endif
520#ifdef BOOST_THREAD_USES_CHRONO
521 template <class Rep, class Period>
522 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
523 {
524 return try_lock_until(chrono::steady_clock::now() + rel_time);
525 }
526 template <class Clock, class Duration>
527 bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
528 {
529 using namespace chrono;
530 system_clock::time_point s_now = system_clock::now();
531 typename Clock::time_point c_now = Clock::now();
532 return try_lock_until(s_now + ceil<system_clock::duration>(t - c_now));
533 }
534 template <class Duration>
535 bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
536 {
537 using namespace chrono;
538 typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt;
539 return try_lock_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch())));
540 }
541 bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp)
542 {
543 for(;;)
544 {
545 state_data old_state=state;
546
547 for(;;)
548 {
549 state_data new_state=old_state;
550 if(new_state.shared_count || new_state.exclusive)
551 {
552 ++new_state.exclusive_waiting;
553 if(!new_state.exclusive_waiting)
554 {
555 boost::throw_exception(boost::lock_error());
556 }
557
558 new_state.exclusive_waiting_blocked=true;
559 }
560 else
561 {
562 new_state.exclusive=true;
563 }
564
565 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
566 if(current_state==old_state)
567 {
568 break;
569 }
570 old_state=current_state;
571 }
572
573 if(!old_state.shared_count && !old_state.exclusive)
574 {
575 return true;
576 }
577 #ifndef UNDER_CE
578 const bool wait_all = true;
579 #else
580 const bool wait_all = false;
581 #endif
582
583 chrono::system_clock::time_point n = chrono::system_clock::now();
584 unsigned long wait_res;
585 if (tp>n) {
586 chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
587 wait_res=detail::win32::WaitForMultipleObjectsEx(2,semaphores,wait_all,
588 static_cast<unsigned long>(rel_time.count()), 0);
589 } else {
590 wait_res=detail::win32::timeout;
591 }
592 if(wait_res==detail::win32::timeout)
593 {
594 for(;;)
595 {
596 bool must_notify = false;
597 state_data new_state=old_state;
598 if(new_state.shared_count || new_state.exclusive)
599 {
600 if(new_state.exclusive_waiting)
601 {
602 if(!--new_state.exclusive_waiting)
603 {
604 new_state.exclusive_waiting_blocked=false;
605 must_notify = true;
606 }
607 }
608 }
609 else
610 {
611 new_state.exclusive=true;
612 }
613
614 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
615 if (must_notify)
616 {
617 BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
618 }
619 if(current_state==old_state)
620 {
621 break;
622 }
623 old_state=current_state;
624 }
625 if(!old_state.shared_count && !old_state.exclusive)
626 {
627 return true;
628 }
629 return false;
630 }
631 BOOST_ASSERT(wait_res<2);
632 }
633 }
634#endif
635
636 void unlock()
637 {
638 state_data old_state=state;
639 for(;;)
640 {
641 state_data new_state=old_state;
642 new_state.exclusive=false;
643 if(new_state.exclusive_waiting)
644 {
645 --new_state.exclusive_waiting;
646 new_state.exclusive_waiting_blocked=false;
647 }
648 new_state.shared_waiting=0;
649
650 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
651 if(current_state==old_state)
652 {
653 break;
654 }
655 old_state=current_state;
656 }
657 release_waiters(old_state);
658 }
659
660 void lock_upgrade()
661 {
662 for(;;)
663 {
664 state_data old_state=state;
665 for(;;)
666 {
667 state_data new_state=old_state;
668 if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
669 {
670 ++new_state.shared_waiting;
671 if(!new_state.shared_waiting)
672 {
673 boost::throw_exception(boost::lock_error());
674 }
675 }
676 else
677 {
678 ++new_state.shared_count;
679 if(!new_state.shared_count)
680 {
681 boost::throw_exception(boost::lock_error());
682 }
683 new_state.upgrade=true;
684 }
685
686 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
687 if(current_state==old_state)
688 {
689 break;
690 }
691 old_state=current_state;
692 }
693
694 if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade))
695 {
696 return;
697 }
698
699 BOOST_VERIFY(!detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],detail::win32::infinite, 0));
700 }
701 }
702
703 bool try_lock_upgrade()
704 {
705 state_data old_state=state;
706 for(;;)
707 {
708 state_data new_state=old_state;
709 if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
710 {
711 return false;
712 }
713 else
714 {
715 ++new_state.shared_count;
716 if(!new_state.shared_count)
717 {
718 return false;
719 }
720 new_state.upgrade=true;
721 }
722
723 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
724 if(current_state==old_state)
725 {
726 break;
727 }
728 old_state=current_state;
729 }
730 return true;
731 }
732
733 void unlock_upgrade()
734 {
735 state_data old_state=state;
736 for(;;)
737 {
738 state_data new_state=old_state;
739 new_state.upgrade=false;
740 new_state.shared_waiting=0;
741 bool const last_reader=!--new_state.shared_count;
742
743 if(last_reader)
744 {
745 if(new_state.exclusive_waiting)
746 {
747 --new_state.exclusive_waiting;
748 new_state.exclusive_waiting_blocked=false;
749 }
750 }
751
752 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
753 if(current_state==old_state)
754 {
755 if(last_reader)
756 {
757 release_waiters(old_state);
758 }
759 else {
760 release_shared_waiters(old_state);
761 }
762 // #7720
763 //else {
764 // release_waiters(old_state);
765 //}
766 break;
767 }
768 old_state=current_state;
769 }
770 }
771
772 void unlock_upgrade_and_lock()
773 {
774 state_data old_state=state;
775 for(;;)
776 {
777 state_data new_state=old_state;
778 bool const last_reader=!--new_state.shared_count;
779
780 if(last_reader)
781 {
782 new_state.upgrade=false;
783 new_state.exclusive=true;
784 }
785
786 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
787 if(current_state==old_state)
788 {
789 if(!last_reader)
790 {
791 BOOST_VERIFY(!detail::win32::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite, 0));
792 }
793 break;
794 }
795 old_state=current_state;
796 }
797 }
798
799 void unlock_and_lock_upgrade()
800 {
801 state_data old_state=state;
802 for(;;)
803 {
804 state_data new_state=old_state;
805 new_state.exclusive=false;
806 new_state.upgrade=true;
807 ++new_state.shared_count;
808 if(new_state.exclusive_waiting)
809 {
810 --new_state.exclusive_waiting;
811 new_state.exclusive_waiting_blocked=false;
812 }
813 new_state.shared_waiting=0;
814
815 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
816 if(current_state==old_state)
817 {
818 break;
819 }
820 old_state=current_state;
821 }
822 release_waiters(old_state);
823 }
824// bool try_unlock_upgrade_and_lock()
825// {
826// return false;
827// }
828//#ifdef BOOST_THREAD_USES_CHRONO
829// template <class Rep, class Period>
830// bool
831// try_unlock_upgrade_and_lock_for(
832// const chrono::duration<Rep, Period>& rel_time)
833// {
834// return try_unlock_upgrade_and_lock_until(
835// chrono::steady_clock::now() + rel_time);
836// }
837// template <class Clock, class Duration>
838// bool
839// try_unlock_upgrade_and_lock_until(
840// const chrono::time_point<Clock, Duration>& abs_time)
841// {
842// return false;
843// }
844//#endif
845
846 void unlock_and_lock_shared()
847 {
848 state_data old_state=state;
849 for(;;)
850 {
851 state_data new_state=old_state;
852 new_state.exclusive=false;
853 ++new_state.shared_count;
854 if(new_state.exclusive_waiting)
855 {
856 --new_state.exclusive_waiting;
857 new_state.exclusive_waiting_blocked=false;
858 }
859 new_state.shared_waiting=0;
860
861 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
862 if(current_state==old_state)
863 {
864 break;
865 }
866 old_state=current_state;
867 }
868 release_waiters(old_state);
869 }
870 void unlock_upgrade_and_lock_shared()
871 {
872 state_data old_state=state;
873 for(;;)
874 {
875 state_data new_state=old_state;
876 new_state.upgrade=false;
877 if(new_state.exclusive_waiting)
878 {
879 --new_state.exclusive_waiting;
880 new_state.exclusive_waiting_blocked=false;
881 }
882 new_state.shared_waiting=0;
883
884 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
885 if(current_state==old_state)
886 {
887 break;
888 }
889 old_state=current_state;
890 }
891 release_waiters(old_state);
892 }
893
894 };
895 typedef shared_mutex upgrade_mutex;
896
897}
898
899#include <boost/config/abi_suffix.hpp>
900
901#endif