1#ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
2#define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
3
4// (C) Copyright 2006-8 Anthony Williams
5// (C) Copyright 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/static_assert.hpp>
13#include <boost/thread/mutex.hpp>
14#include <boost/thread/condition_variable.hpp>
15#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
16#include <boost/thread/detail/thread_interruption.hpp>
17#endif
18#ifdef BOOST_THREAD_USES_CHRONO
19#include <boost/chrono/system_clocks.hpp>
20#include <boost/chrono/ceil.hpp>
21#endif
22#include <boost/thread/detail/delete.hpp>
23#include <boost/assert.hpp>
24
25#include <boost/config/abi_prefix.hpp>
26
27namespace boost
28{
29 class shared_mutex
30 {
31 private:
32 class state_data
33 {
34 public:
35 state_data () :
36 shared_count(0),
37 exclusive(false),
38 upgrade(false),
39 exclusive_waiting_blocked(false)
40 {}
41
42 void assert_free() const
43 {
44 BOOST_ASSERT( ! exclusive );
45 BOOST_ASSERT( ! upgrade );
46 BOOST_ASSERT( shared_count==0 );
47 }
48
49 void assert_locked() const
50 {
51 BOOST_ASSERT( exclusive );
52 BOOST_ASSERT( shared_count==0 );
53 BOOST_ASSERT( ! upgrade );
54 }
55
56 void assert_lock_shared () const
57 {
58 BOOST_ASSERT( ! exclusive );
59 BOOST_ASSERT( shared_count>0 );
60 //BOOST_ASSERT( (! upgrade) || (shared_count>1));
61 // if upgraded there are at least 2 threads sharing the mutex,
62 // except when unlock_upgrade_and_lock has decreased the number of readers but has not taken yet exclusive ownership.
63 }
64
65 void assert_lock_upgraded () const
66 {
67 BOOST_ASSERT( ! exclusive );
68 BOOST_ASSERT( upgrade );
69 BOOST_ASSERT( shared_count>0 );
70 }
71
72 void assert_lock_not_upgraded () const
73 {
74 BOOST_ASSERT( ! upgrade );
75 }
76
77 bool can_lock () const
78 {
79 return ! (shared_count || exclusive);
80 }
81
82 void exclusive_blocked (bool blocked)
83 {
84 exclusive_waiting_blocked = blocked;
85 }
86
87 void lock ()
88 {
89 exclusive = true;
90 }
91
92 void unlock ()
93 {
94 exclusive = false;
95 exclusive_waiting_blocked = false;
96 }
97
98 bool can_lock_shared () const
99 {
100 return ! (exclusive || exclusive_waiting_blocked);
101 }
102
103 bool more_shared () const
104 {
105 return shared_count > 0 ;
106 }
107 unsigned get_shared_count () const
108 {
109 return shared_count ;
110 }
111 unsigned lock_shared ()
112 {
113 return ++shared_count;
114 }
115
116
117 void unlock_shared ()
118 {
119 --shared_count;
120 }
121
122 bool unlock_shared_downgrades()
123 {
124 if (upgrade) {
125 upgrade=false;
126 exclusive=true;
127 return true;
128 } else {
129 exclusive_waiting_blocked=false;
130 return false;
131 }
132 }
133
134 void lock_upgrade ()
135 {
136 ++shared_count;
137 upgrade=true;
138 }
139 bool can_lock_upgrade () const
140 {
141 return ! (exclusive || exclusive_waiting_blocked || upgrade);
142 }
143
144 void unlock_upgrade ()
145 {
146 upgrade=false;
147 --shared_count;
148 }
149
150 //private:
151 unsigned shared_count;
152 bool exclusive;
153 bool upgrade;
154 bool exclusive_waiting_blocked;
155 };
156
157
158
159 state_data state;
160 boost::mutex state_change;
161 boost::condition_variable shared_cond;
162 boost::condition_variable exclusive_cond;
163 boost::condition_variable upgrade_cond;
164
165 void release_waiters()
166 {
167 exclusive_cond.notify_one();
168 shared_cond.notify_all();
169 }
170
171 public:
172
173 BOOST_THREAD_NO_COPYABLE(shared_mutex)
174
175 shared_mutex()
176 {
177 }
178
179 ~shared_mutex()
180 {
181 }
182
183 void lock_shared()
184 {
185#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
186 boost::this_thread::disable_interruption do_not_disturb;
187#endif
188 boost::unique_lock<boost::mutex> lk(state_change);
189 while(!state.can_lock_shared())
190 {
191 shared_cond.wait(lk);
192 }
193 state.lock_shared();
194 }
195
196 bool try_lock_shared()
197 {
198 boost::unique_lock<boost::mutex> lk(state_change);
199
200 if(!state.can_lock_shared())
201 {
202 return false;
203 }
204 state.lock_shared();
205 return true;
206 }
207
208#if defined BOOST_THREAD_USES_DATETIME
209 bool timed_lock_shared(system_time const& timeout)
210 {
211#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
212 boost::this_thread::disable_interruption do_not_disturb;
213#endif
214 boost::unique_lock<boost::mutex> lk(state_change);
215
216 while(!state.can_lock_shared())
217 {
218 if(!shared_cond.timed_wait(lk,timeout))
219 {
220 return false;
221 }
222 }
223 state.lock_shared();
224 return true;
225 }
226
227 template<typename TimeDuration>
228 bool timed_lock_shared(TimeDuration const & relative_time)
229 {
230 return timed_lock_shared(get_system_time()+relative_time);
231 }
232#endif
233#ifdef BOOST_THREAD_USES_CHRONO
234 template <class Rep, class Period>
235 bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
236 {
237 return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
238 }
239 template <class Clock, class Duration>
240 bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time)
241 {
242#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
243 boost::this_thread::disable_interruption do_not_disturb;
244#endif
245 boost::unique_lock<boost::mutex> lk(state_change);
246
247 while(!state.can_lock_shared())
248 //while(state.exclusive || state.exclusive_waiting_blocked)
249 {
250 if(cv_status::timeout==shared_cond.wait_until(lk,abs_time))
251 {
252 return false;
253 }
254 }
255 state.lock_shared();
256 return true;
257 }
258#endif
259 void unlock_shared()
260 {
261 boost::unique_lock<boost::mutex> lk(state_change);
262 state.assert_lock_shared();
263 state.unlock_shared();
264 if (! state.more_shared())
265 {
266 if (state.upgrade)
267 {
268 // As there is a thread doing a unlock_upgrade_and_lock that is waiting for ! state.more_shared()
269 // avoid other threads to lock, lock_upgrade or lock_shared, so only this thread is notified.
270 state.upgrade=false;
271 state.exclusive=true;
272 //lk.unlock();
273 upgrade_cond.notify_one();
274 }
275 else
276 {
277 state.exclusive_waiting_blocked=false;
278 //lk.unlock();
279 }
280 release_waiters();
281 }
282 }
283
284 void lock()
285 {
286#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
287 boost::this_thread::disable_interruption do_not_disturb;
288#endif
289 boost::unique_lock<boost::mutex> lk(state_change);
290
291 while (state.shared_count || state.exclusive)
292 {
293 state.exclusive_waiting_blocked=true;
294 exclusive_cond.wait(lk);
295 }
296 state.exclusive=true;
297 }
298
299#if defined BOOST_THREAD_USES_DATETIME
300 bool timed_lock(system_time const& timeout)
301 {
302#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
303 boost::this_thread::disable_interruption do_not_disturb;
304#endif
305 boost::unique_lock<boost::mutex> lk(state_change);
306
307 while(state.shared_count || state.exclusive)
308 {
309 state.exclusive_waiting_blocked=true;
310 if(!exclusive_cond.timed_wait(lk,timeout))
311 {
312 if(state.shared_count || state.exclusive)
313 {
314 state.exclusive_waiting_blocked=false;
315 release_waiters();
316 return false;
317 }
318 break;
319 }
320 }
321 state.exclusive=true;
322 return true;
323 }
324
325 template<typename TimeDuration>
326 bool timed_lock(TimeDuration const & relative_time)
327 {
328 return timed_lock(get_system_time()+relative_time);
329 }
330#endif
331#ifdef BOOST_THREAD_USES_CHRONO
332 template <class Rep, class Period>
333 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
334 {
335 return try_lock_until(chrono::steady_clock::now() + rel_time);
336 }
337 template <class Clock, class Duration>
338 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
339 {
340#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
341 boost::this_thread::disable_interruption do_not_disturb;
342#endif
343 boost::unique_lock<boost::mutex> lk(state_change);
344
345 while(state.shared_count || state.exclusive)
346 {
347 state.exclusive_waiting_blocked=true;
348 if(cv_status::timeout == exclusive_cond.wait_until(lk,abs_time))
349 {
350 if(state.shared_count || state.exclusive)
351 {
352 state.exclusive_waiting_blocked=false;
353 release_waiters();
354 return false;
355 }
356 break;
357 }
358 }
359 state.exclusive=true;
360 return true;
361 }
362#endif
363
364 bool try_lock()
365 {
366 boost::unique_lock<boost::mutex> lk(state_change);
367
368 if(state.shared_count || state.exclusive)
369 {
370 return false;
371 }
372 else
373 {
374 state.exclusive=true;
375 return true;
376 }
377
378 }
379
380 void unlock()
381 {
382 boost::unique_lock<boost::mutex> lk(state_change);
383 state.assert_locked();
384 state.exclusive=false;
385 state.exclusive_waiting_blocked=false;
386 state.assert_free();
387 release_waiters();
388 }
389
390 void lock_upgrade()
391 {
392#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
393 boost::this_thread::disable_interruption do_not_disturb;
394#endif
395 boost::unique_lock<boost::mutex> lk(state_change);
396 while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
397 {
398 shared_cond.wait(lk);
399 }
400 state.lock_shared();
401 state.upgrade=true;
402 }
403
404#if defined BOOST_THREAD_USES_DATETIME
405 bool timed_lock_upgrade(system_time const& timeout)
406 {
407#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
408 boost::this_thread::disable_interruption do_not_disturb;
409#endif
410 boost::unique_lock<boost::mutex> lk(state_change);
411 while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
412 {
413 if(!shared_cond.timed_wait(lk,timeout))
414 {
415 if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
416 {
417 return false;
418 }
419 break;
420 }
421 }
422 state.lock_shared();
423 state.upgrade=true;
424 return true;
425 }
426
427 template<typename TimeDuration>
428 bool timed_lock_upgrade(TimeDuration const & relative_time)
429 {
430 return timed_lock_upgrade(get_system_time()+relative_time);
431 }
432#endif
433#ifdef BOOST_THREAD_USES_CHRONO
434 template <class Rep, class Period>
435 bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time)
436 {
437 return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time);
438 }
439 template <class Clock, class Duration>
440 bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time)
441 {
442#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
443 boost::this_thread::disable_interruption do_not_disturb;
444#endif
445 boost::unique_lock<boost::mutex> lk(state_change);
446 while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
447 {
448 if(cv_status::timeout == shared_cond.wait_until(lk,abs_time))
449 {
450 if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
451 {
452 return false;
453 }
454 break;
455 }
456 }
457 state.lock_shared();
458 state.upgrade=true;
459 return true;
460 }
461#endif
462 bool try_lock_upgrade()
463 {
464 boost::unique_lock<boost::mutex> lk(state_change);
465 if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
466 {
467 return false;
468 }
469 else
470 {
471 state.lock_shared();
472 state.upgrade=true;
473 state.assert_lock_upgraded();
474 return true;
475 }
476 }
477
478 void unlock_upgrade()
479 {
480 boost::unique_lock<boost::mutex> lk(state_change);
481 //state.upgrade=false;
482 state.unlock_upgrade();
483 if(! state.more_shared() )
484 {
485 state.exclusive_waiting_blocked=false;
486 release_waiters();
487 } else {
488 shared_cond.notify_all();
489 }
490 }
491
492 // Upgrade <-> Exclusive
493 void unlock_upgrade_and_lock()
494 {
495#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
496 boost::this_thread::disable_interruption do_not_disturb;
497#endif
498 boost::unique_lock<boost::mutex> lk(state_change);
499 state.assert_lock_upgraded();
500 state.unlock_shared();
501 while (state.more_shared())
502 {
503 upgrade_cond.wait(lk);
504 }
505 state.upgrade=false;
506 state.exclusive=true;
507 state.assert_locked();
508 }
509
510 void unlock_and_lock_upgrade()
511 {
512 boost::unique_lock<boost::mutex> lk(state_change);
513 state.assert_locked();
514 state.exclusive=false;
515 state.upgrade=true;
516 state.lock_shared();
517 state.exclusive_waiting_blocked=false;
518 state.assert_lock_upgraded();
519 release_waiters();
520 }
521
522 bool try_unlock_upgrade_and_lock()
523 {
524 boost::unique_lock<boost::mutex> lk(state_change);
525 state.assert_lock_upgraded();
526 if( !state.exclusive
527 && !state.exclusive_waiting_blocked
528 && state.upgrade
529 && state.shared_count==1)
530 {
531 state.shared_count=0;
532 state.exclusive=true;
533 state.upgrade=false;
534 state.assert_locked();
535 return true;
536 }
537 return false;
538 }
539#ifdef BOOST_THREAD_USES_CHRONO
540 template <class Rep, class Period>
541 bool
542 try_unlock_upgrade_and_lock_for(
543 const chrono::duration<Rep, Period>& rel_time)
544 {
545 return try_unlock_upgrade_and_lock_until(
546 chrono::steady_clock::now() + rel_time);
547 }
548 template <class Clock, class Duration>
549 bool
550 try_unlock_upgrade_and_lock_until(
551 const chrono::time_point<Clock, Duration>& abs_time)
552 {
553#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
554 boost::this_thread::disable_interruption do_not_disturb;
555#endif
556 boost::unique_lock<boost::mutex> lk(state_change);
557 state.assert_lock_upgraded();
558 if (state.shared_count != 1)
559 {
560 for (;;)
561 {
562 cv_status status = shared_cond.wait_until(lk,abs_time);
563 if (state.shared_count == 1)
564 break;
565 if(status == cv_status::timeout)
566 return false;
567 }
568 }
569 state.upgrade=false;
570 state.exclusive=true;
571 state.exclusive_waiting_blocked=false;
572 state.shared_count=0;
573 return true;
574 }
575#endif
576
577 // Shared <-> Exclusive
578 void unlock_and_lock_shared()
579 {
580 boost::unique_lock<boost::mutex> lk(state_change);
581 state.assert_locked();
582 state.exclusive=false;
583 state.lock_shared();
584 state.exclusive_waiting_blocked=false;
585 release_waiters();
586 }
587
588#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
589 bool try_unlock_shared_and_lock()
590 {
591 boost::unique_lock<boost::mutex> lk(state_change);
592 state.assert_lock_shared();
593 if( !state.exclusive
594 && !state.exclusive_waiting_blocked
595 && !state.upgrade
596 && state.shared_count==1)
597 {
598 state.shared_count=0;
599 state.exclusive=true;
600 return true;
601 }
602 return false;
603 }
604#ifdef BOOST_THREAD_USES_CHRONO
605 template <class Rep, class Period>
606 bool
607 try_unlock_shared_and_lock_for(
608 const chrono::duration<Rep, Period>& rel_time)
609 {
610 return try_unlock_shared_and_lock_until(
611 chrono::steady_clock::now() + rel_time);
612 }
613 template <class Clock, class Duration>
614 bool
615 try_unlock_shared_and_lock_until(
616 const chrono::time_point<Clock, Duration>& abs_time)
617 {
618#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
619 boost::this_thread::disable_interruption do_not_disturb;
620#endif
621 boost::unique_lock<boost::mutex> lk(state_change);
622 state.assert_lock_shared();
623 if (state.shared_count != 1)
624 {
625 for (;;)
626 {
627 cv_status status = shared_cond.wait_until(lk,abs_time);
628 if (state.shared_count == 1)
629 break;
630 if(status == cv_status::timeout)
631 return false;
632 }
633 }
634 state.upgrade=false;
635 state.exclusive=true;
636 state.exclusive_waiting_blocked=false;
637 state.shared_count=0;
638 return true;
639 }
640#endif
641#endif
642
643 // Shared <-> Upgrade
644 void unlock_upgrade_and_lock_shared()
645 {
646 boost::unique_lock<boost::mutex> lk(state_change);
647 state.assert_lock_upgraded();
648 state.upgrade=false;
649 state.exclusive_waiting_blocked=false;
650 release_waiters();
651 }
652
653#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
654 bool try_unlock_shared_and_lock_upgrade()
655 {
656 boost::unique_lock<boost::mutex> lk(state_change);
657 state.assert_lock_shared();
658 if( !state.exclusive
659 && !state.exclusive_waiting_blocked
660 && !state.upgrade
661 )
662 {
663 state.upgrade=true;
664 return true;
665 }
666 return false;
667 }
668#ifdef BOOST_THREAD_USES_CHRONO
669 template <class Rep, class Period>
670 bool
671 try_unlock_shared_and_lock_upgrade_for(
672 const chrono::duration<Rep, Period>& rel_time)
673 {
674 return try_unlock_shared_and_lock_upgrade_until(
675 chrono::steady_clock::now() + rel_time);
676 }
677 template <class Clock, class Duration>
678 bool
679 try_unlock_shared_and_lock_upgrade_until(
680 const chrono::time_point<Clock, Duration>& abs_time)
681 {
682#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
683 boost::this_thread::disable_interruption do_not_disturb;
684#endif
685 boost::unique_lock<boost::mutex> lk(state_change);
686 state.assert_lock_shared();
687 if( state.exclusive
688 || state.exclusive_waiting_blocked
689 || state.upgrade
690 )
691 {
692 for (;;)
693 {
694 cv_status status = exclusive_cond.wait_until(lk,abs_time);
695 if( ! state.exclusive
696 && ! state.exclusive_waiting_blocked
697 && ! state.upgrade
698 )
699 break;
700 if(status == cv_status::timeout)
701 return false;
702 }
703 }
704 state.upgrade=true;
705 return true;
706 }
707#endif
708#endif
709 };
710
711 typedef shared_mutex upgrade_mutex;
712}
713
714#include <boost/config/abi_suffix.hpp>
715
716#endif
717