• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef BOOST_THREAD_V2_SHARED_MUTEX_HPP
2 #define BOOST_THREAD_V2_SHARED_MUTEX_HPP
3 
4 //  shared_mutex.hpp
5 //
6 // Copyright Howard Hinnant 2007-2010.
7 // Copyright Vicente J. Botet Escriba 2012.
8 //
9 //  Distributed under the Boost Software License, Version 1.0. (See
10 //  accompanying file LICENSE_1_0.txt or copy at
11 //  http://www.boost.org/LICENSE_1_0.txt)
12 
13 /*
14 <shared_mutex> synopsis
15 
16 namespace boost
17 {
18 namespace thread_v2
19 {
20 
21 class shared_mutex
22 {
23 public:
24 
25     shared_mutex();
26     ~shared_mutex();
27 
28     shared_mutex(const shared_mutex&) = delete;
29     shared_mutex& operator=(const shared_mutex&) = delete;
30 
31     // Exclusive ownership
32 
33     void lock();
34     bool try_lock();
35     template <class Rep, class Period>
36         bool try_lock_for(const boost::chrono::duration<Rep, Period>& rel_time);
37     template <class Clock, class Duration>
38         bool
39         try_lock_until(
40                       const boost::chrono::time_point<Clock, Duration>& abs_time);
41     void unlock();
42 
43     // Shared ownership
44 
45     void lock_shared();
46     bool try_lock_shared();
47     template <class Rep, class Period>
48         bool
49         try_lock_shared_for(const boost::chrono::duration<Rep, Period>& rel_time);
50     template <class Clock, class Duration>
51         bool
52         try_lock_shared_until(
53                       const boost::chrono::time_point<Clock, Duration>& abs_time);
54     void unlock_shared();
55 };
56 
57 class upgrade_mutex
58 {
59 public:
60 
61     upgrade_mutex();
62     ~upgrade_mutex();
63 
64     upgrade_mutex(const upgrade_mutex&) = delete;
65     upgrade_mutex& operator=(const upgrade_mutex&) = delete;
66 
67     // Exclusive ownership
68 
69     void lock();
70     bool try_lock();
71     template <class Rep, class Period>
72         bool try_lock_for(const boost::chrono::duration<Rep, Period>& rel_time);
73     template <class Clock, class Duration>
74         bool
75         try_lock_until(
76                       const boost::chrono::time_point<Clock, Duration>& abs_time);
77     void unlock();
78 
79     // Shared ownership
80 
81     void lock_shared();
82     bool try_lock_shared();
83     template <class Rep, class Period>
84         bool
85         try_lock_shared_for(const boost::chrono::duration<Rep, Period>& rel_time);
86     template <class Clock, class Duration>
87         bool
88         try_lock_shared_until(
89                       const boost::chrono::time_point<Clock, Duration>& abs_time);
90     void unlock_shared();
91 
92     // Upgrade ownership
93 
94     void lock_upgrade();
95     bool try_lock_upgrade();
96     template <class Rep, class Period>
97         bool
98         try_lock_upgrade_for(
99                             const boost::chrono::duration<Rep, Period>& rel_time);
100     template <class Clock, class Duration>
101         bool
102         try_lock_upgrade_until(
103                       const boost::chrono::time_point<Clock, Duration>& abs_time);
104     void unlock_upgrade();
105 
106     // Shared <-> Exclusive
107 
108     bool try_unlock_shared_and_lock();
109     template <class Rep, class Period>
110         bool
111         try_unlock_shared_and_lock_for(
112                             const boost::chrono::duration<Rep, Period>& rel_time);
113     template <class Clock, class Duration>
114         bool
115         try_unlock_shared_and_lock_until(
116                       const boost::chrono::time_point<Clock, Duration>& abs_time);
117     void unlock_and_lock_shared();
118 
119     // Shared <-> Upgrade
120 
121     bool try_unlock_shared_and_lock_upgrade();
122     template <class Rep, class Period>
123         bool
124         try_unlock_shared_and_lock_upgrade_for(
125                             const boost::chrono::duration<Rep, Period>& rel_time);
126     template <class Clock, class Duration>
127         bool
128         try_unlock_shared_and_lock_upgrade_until(
129                       const boost::chrono::time_point<Clock, Duration>& abs_time);
130     void unlock_upgrade_and_lock_shared();
131 
132     // Upgrade <-> Exclusive
133 
134     void unlock_upgrade_and_lock();
135     bool try_unlock_upgrade_and_lock();
136     template <class Rep, class Period>
137         bool
138         try_unlock_upgrade_and_lock_for(
139                             const boost::chrono::duration<Rep, Period>& rel_time);
140     template <class Clock, class Duration>
141         bool
142         try_unlock_upgrade_and_lock_until(
143                       const boost::chrono::time_point<Clock, Duration>& abs_time);
144     void unlock_and_lock_upgrade();
145 };
146 
147 }  // thread_v2
148 }  // boost
149 
150  */
151 
152 #include <boost/thread/detail/config.hpp>
153 #include <boost/thread/mutex.hpp>
154 #include <boost/thread/condition_variable.hpp>
155 #include <boost/thread/mutex.hpp>
156 #ifdef BOOST_THREAD_USES_CHRONO
157 #include <boost/chrono.hpp>
158 #endif
159 #include <climits>
160 #include <boost/system/system_error.hpp>
161 #include <boost/bind/bind.hpp>
162 
163 namespace boost {
164   namespace thread_v2 {
165 
166     class shared_mutex
167     {
168       typedef boost::mutex              mutex_t;
169       typedef boost::condition_variable cond_t;
170       typedef unsigned                  count_t;
171 
172       mutex_t mut_;
173       cond_t  gate1_;
174       // the gate2_ condition variable is only used by functions that
175       // have taken write_entered_ but are waiting for no_readers()
176       cond_t  gate2_;
177       count_t state_;
178 
179       static const count_t write_entered_ = 1U << (sizeof(count_t)*CHAR_BIT - 1);
180       static const count_t n_readers_ = ~write_entered_;
181 
no_writer() const182       bool no_writer() const
183       {
184         return (state_ & write_entered_) == 0;
185       }
186 
one_writer() const187       bool one_writer() const
188       {
189         return (state_ & write_entered_) != 0;
190       }
191 
no_writer_no_readers() const192       bool no_writer_no_readers() const
193       {
194         //return (state_ & write_entered_) == 0 &&
195         //       (state_ & n_readers_) == 0;
196         return state_ == 0;
197       }
198 
no_writer_no_max_readers() const199       bool no_writer_no_max_readers() const
200       {
201         return (state_ & write_entered_) == 0 &&
202                (state_ & n_readers_) != n_readers_;
203       }
204 
no_readers() const205       bool no_readers() const
206       {
207         return (state_ & n_readers_) == 0;
208       }
209 
one_or_more_readers() const210       bool one_or_more_readers() const
211       {
212         return (state_ & n_readers_) > 0;
213       }
214 
215       shared_mutex(shared_mutex const&);
216       shared_mutex& operator=(shared_mutex const&);
217 
218     public:
219       shared_mutex();
220       ~shared_mutex();
221 
222       // Exclusive ownership
223 
224       void lock();
225       bool try_lock();
226 #ifdef BOOST_THREAD_USES_CHRONO
227       template <class Rep, class Period>
try_lock_for(const boost::chrono::duration<Rep,Period> & rel_time)228       bool try_lock_for(const boost::chrono::duration<Rep, Period>& rel_time)
229       {
230         return try_lock_until(chrono::steady_clock::now() + rel_time);
231       }
232       template <class Clock, class Duration>
233       bool try_lock_until(
234           const boost::chrono::time_point<Clock, Duration>& abs_time);
235 #endif
236 #if defined BOOST_THREAD_USES_DATETIME
237       template<typename T>
238       bool timed_lock(T const & abs_or_rel_time);
239 #endif
240       void unlock();
241 
242       // Shared ownership
243 
244       void lock_shared();
245       bool try_lock_shared();
246 #ifdef BOOST_THREAD_USES_CHRONO
247       template <class Rep, class Period>
try_lock_shared_for(const boost::chrono::duration<Rep,Period> & rel_time)248       bool try_lock_shared_for(const boost::chrono::duration<Rep, Period>& rel_time)
249       {
250         return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
251       }
252       template <class Clock, class Duration>
253       bool try_lock_shared_until(
254           const boost::chrono::time_point<Clock, Duration>& abs_time);
255 #endif
256 #if defined BOOST_THREAD_USES_DATETIME
257       template<typename T>
258       bool timed_lock_shared(T const & abs_or_rel_time);
259 #endif
260       void unlock_shared();
261     };
262 
shared_mutex()263     inline shared_mutex::shared_mutex()
264     : state_(0)
265     {
266     }
267 
~shared_mutex()268     inline shared_mutex::~shared_mutex()
269     {
270       boost::lock_guard<mutex_t> _(mut_);
271     }
272 
273     // Exclusive ownership
274 
lock()275     inline void shared_mutex::lock()
276     {
277       boost::unique_lock<mutex_t> lk(mut_);
278       gate1_.wait(lk, boost::bind(&shared_mutex::no_writer, boost::ref(*this)));
279       state_ |= write_entered_;
280       gate2_.wait(lk, boost::bind(&shared_mutex::no_readers, boost::ref(*this)));
281     }
282 
try_lock()283     inline bool shared_mutex::try_lock()
284     {
285       boost::unique_lock<mutex_t> lk(mut_);
286       if (!no_writer_no_readers())
287       {
288         return false;
289       }
290       state_ = write_entered_;
291       return true;
292     }
293 
294 #ifdef BOOST_THREAD_USES_CHRONO
295     template <class Clock, class Duration>
try_lock_until(const boost::chrono::time_point<Clock,Duration> & abs_time)296     bool shared_mutex::try_lock_until(
297         const boost::chrono::time_point<Clock, Duration>& abs_time)
298     {
299       boost::unique_lock<mutex_t> lk(mut_);
300       if (!gate1_.wait_until(lk, abs_time, boost::bind(
301             &shared_mutex::no_writer, boost::ref(*this))))
302       {
303         return false;
304       }
305       state_ |= write_entered_;
306       if (!gate2_.wait_until(lk, abs_time, boost::bind(
307             &shared_mutex::no_readers, boost::ref(*this))))
308       {
309         state_ &= ~write_entered_;
310         return false;
311       }
312       return true;
313     }
314 #endif
315 
316 #if defined BOOST_THREAD_USES_DATETIME
317     template<typename T>
timed_lock(T const & abs_or_rel_time)318     bool shared_mutex::timed_lock(T const & abs_or_rel_time)
319     {
320       boost::unique_lock<mutex_t> lk(mut_);
321       if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind(
322             &shared_mutex::no_writer, boost::ref(*this))))
323       {
324         return false;
325       }
326       state_ |= write_entered_;
327       if (!gate2_.timed_wait(lk, abs_or_rel_time, boost::bind(
328             &shared_mutex::no_readers, boost::ref(*this))))
329       {
330         state_ &= ~write_entered_;
331         return false;
332       }
333       return true;
334     }
335 #endif
336 
unlock()337     inline void shared_mutex::unlock()
338     {
339       boost::lock_guard<mutex_t> _(mut_);
340       BOOST_ASSERT(one_writer());
341       BOOST_ASSERT(no_readers());
342       state_ = 0;
343       // notify all since multiple *lock_shared*() calls may be able
344       // to proceed in response to this notification
345       gate1_.notify_all();
346     }
347 
348     // Shared ownership
349 
lock_shared()350     inline void shared_mutex::lock_shared()
351     {
352       boost::unique_lock<mutex_t> lk(mut_);
353       gate1_.wait(lk, boost::bind(&shared_mutex::no_writer_no_max_readers, boost::ref(*this)));
354       count_t num_readers = (state_ & n_readers_) + 1;
355       state_ &= ~n_readers_;
356       state_ |= num_readers;
357     }
358 
try_lock_shared()359     inline bool shared_mutex::try_lock_shared()
360     {
361       boost::unique_lock<mutex_t> lk(mut_);
362       if (!no_writer_no_max_readers())
363       {
364         return false;
365       }
366       count_t num_readers = (state_ & n_readers_) + 1;
367       state_ &= ~n_readers_;
368       state_ |= num_readers;
369       return true;
370     }
371 
372 #ifdef BOOST_THREAD_USES_CHRONO
373     template <class Clock, class Duration>
try_lock_shared_until(const boost::chrono::time_point<Clock,Duration> & abs_time)374     bool shared_mutex::try_lock_shared_until(
375         const boost::chrono::time_point<Clock, Duration>& abs_time)
376     {
377       boost::unique_lock<mutex_t> lk(mut_);
378       if (!gate1_.wait_until(lk, abs_time, boost::bind(
379             &shared_mutex::no_writer_no_max_readers, boost::ref(*this))))
380       {
381         return false;
382       }
383       count_t num_readers = (state_ & n_readers_) + 1;
384       state_ &= ~n_readers_;
385       state_ |= num_readers;
386       return true;
387     }
388 #endif
389 
390 #if defined BOOST_THREAD_USES_DATETIME
391     template<typename T>
timed_lock_shared(T const & abs_or_rel_time)392     bool shared_mutex::timed_lock_shared(T const & abs_or_rel_time)
393     {
394       boost::unique_lock<mutex_t> lk(mut_);
395       if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind(
396             &shared_mutex::no_writer_no_max_readers, boost::ref(*this))))
397       {
398         return false;
399       }
400       count_t num_readers = (state_ & n_readers_) + 1;
401       state_ &= ~n_readers_;
402       state_ |= num_readers;
403       return true;
404     }
405 #endif
406 
unlock_shared()407     inline void shared_mutex::unlock_shared()
408     {
409       boost::lock_guard<mutex_t> _(mut_);
410       BOOST_ASSERT(one_or_more_readers());
411       count_t num_readers = (state_ & n_readers_) - 1;
412       state_ &= ~n_readers_;
413       state_ |= num_readers;
414       if (no_writer())
415       {
416         if (num_readers == n_readers_ - 1)
417           gate1_.notify_one();
418       }
419       else
420       {
421         if (num_readers == 0)
422           gate2_.notify_one();
423       }
424     }
425 
426   }  // thread_v2
427 }  // boost
428 
429 namespace boost {
430   namespace thread_v2 {
431 
432     class upgrade_mutex
433     {
434       typedef boost::mutex              mutex_t;
435       typedef boost::condition_variable cond_t;
436       typedef unsigned                  count_t;
437 
438       mutex_t mut_;
439       cond_t  gate1_;
440       // the gate2_ condition variable is only used by functions that
441       // have taken write_entered_ but are waiting for no_readers()
442       cond_t  gate2_;
443       count_t state_;
444 
445       static const unsigned write_entered_ = 1U << (sizeof(count_t)*CHAR_BIT - 1);
446       static const unsigned upgradable_entered_ = write_entered_ >> 1;
447       static const unsigned n_readers_ = ~(write_entered_ | upgradable_entered_);
448 
no_writer() const449       bool no_writer() const
450       {
451         return (state_ & write_entered_) == 0;
452       }
453 
one_writer() const454       bool one_writer() const
455       {
456         return (state_ & write_entered_) != 0;
457       }
458 
no_writer_no_max_readers() const459       bool no_writer_no_max_readers() const
460       {
461         return (state_ & write_entered_) == 0 &&
462                (state_ & n_readers_) != n_readers_;
463       }
464 
no_writer_no_upgrader() const465       bool no_writer_no_upgrader() const
466       {
467         return (state_ & (write_entered_ | upgradable_entered_)) == 0;
468       }
469 
no_writer_no_upgrader_no_readers() const470       bool no_writer_no_upgrader_no_readers() const
471       {
472         //return (state_ & (write_entered_ | upgradable_entered_)) == 0 &&
473         //       (state_ & n_readers_) == 0;
474         return state_ == 0;
475       }
476 
no_writer_no_upgrader_one_reader() const477       bool no_writer_no_upgrader_one_reader() const
478       {
479         //return (state_ & (write_entered_ | upgradable_entered_)) == 0 &&
480         //       (state_ & n_readers_) == 1;
481         return state_ == 1;
482       }
483 
no_writer_no_upgrader_no_max_readers() const484       bool no_writer_no_upgrader_no_max_readers() const
485       {
486         return (state_ & (write_entered_ | upgradable_entered_)) == 0 &&
487                (state_ & n_readers_) != n_readers_;
488       }
489 
no_upgrader() const490       bool no_upgrader() const
491       {
492         return (state_ & upgradable_entered_) == 0;
493       }
494 
one_upgrader() const495       bool one_upgrader() const
496       {
497         return (state_ & upgradable_entered_) != 0;
498       }
499 
no_readers() const500       bool no_readers() const
501       {
502         return (state_ & n_readers_) == 0;
503       }
504 
one_reader() const505       bool one_reader() const
506       {
507         return (state_ & n_readers_) == 1;
508       }
509 
one_or_more_readers() const510       bool one_or_more_readers() const
511       {
512         return (state_ & n_readers_) > 0;
513       }
514 
515       upgrade_mutex(const upgrade_mutex&);
516       upgrade_mutex& operator=(const upgrade_mutex&);
517 
518     public:
519       upgrade_mutex();
520       ~upgrade_mutex();
521 
522       // Exclusive ownership
523 
524       void lock();
525       bool try_lock();
526 #ifdef BOOST_THREAD_USES_CHRONO
527       template <class Rep, class Period>
try_lock_for(const boost::chrono::duration<Rep,Period> & rel_time)528       bool try_lock_for(const boost::chrono::duration<Rep, Period>& rel_time)
529       {
530         return try_lock_until(chrono::steady_clock::now() + rel_time);
531       }
532       template <class Clock, class Duration>
533       bool try_lock_until(
534           const boost::chrono::time_point<Clock, Duration>& abs_time);
535 #endif
536 #if defined BOOST_THREAD_USES_DATETIME
537       template<typename T>
538       bool timed_lock(T const & abs_or_rel_time);
539 #endif
540       void unlock();
541 
542       // Shared ownership
543 
544       void lock_shared();
545       bool try_lock_shared();
546 #ifdef BOOST_THREAD_USES_CHRONO
547       template <class Rep, class Period>
try_lock_shared_for(const boost::chrono::duration<Rep,Period> & rel_time)548       bool try_lock_shared_for(const boost::chrono::duration<Rep, Period>& rel_time)
549       {
550         return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
551       }
552       template <class Clock, class Duration>
553       bool try_lock_shared_until(
554           const boost::chrono::time_point<Clock, Duration>& abs_time);
555 #endif
556 #if defined BOOST_THREAD_USES_DATETIME
557       template<typename T>
558       bool timed_lock_shared(T const & abs_or_rel_time);
559 #endif
560       void unlock_shared();
561 
562       // Upgrade ownership
563 
564       void lock_upgrade();
565       bool try_lock_upgrade();
566 #ifdef BOOST_THREAD_USES_CHRONO
567       template <class Rep, class Period>
try_lock_upgrade_for(const boost::chrono::duration<Rep,Period> & rel_time)568       bool try_lock_upgrade_for(
569           const boost::chrono::duration<Rep, Period>& rel_time)
570       {
571         return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time);
572       }
573       template <class Clock, class Duration>
574       bool try_lock_upgrade_until(
575           const boost::chrono::time_point<Clock, Duration>& abs_time);
576 #endif
577 #if defined BOOST_THREAD_USES_DATETIME
578       template<typename T>
579       bool timed_lock_upgrade(T const & abs_or_rel_time);
580 #endif
581       void unlock_upgrade();
582 
583       // Shared <-> Exclusive
584 
585 #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
586       //bool unlock_shared_and_lock(); // can cause a deadlock if used
587       bool try_unlock_shared_and_lock();
588 #ifdef BOOST_THREAD_USES_CHRONO
589       template <class Rep, class Period>
try_unlock_shared_and_lock_for(const boost::chrono::duration<Rep,Period> & rel_time)590       bool try_unlock_shared_and_lock_for(
591           const boost::chrono::duration<Rep, Period>& rel_time)
592       {
593         return try_unlock_shared_and_lock_until(chrono::steady_clock::now() + rel_time);
594       }
595       template <class Clock, class Duration>
596       bool try_unlock_shared_and_lock_until(
597           const boost::chrono::time_point<Clock, Duration>& abs_time);
598 #endif
599 #endif
600       void unlock_and_lock_shared();
601 
602       // Shared <-> Upgrade
603 
604 #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
605       //bool unlock_shared_and_lock_upgrade(); // can cause a deadlock if used
606       bool try_unlock_shared_and_lock_upgrade();
607 #ifdef BOOST_THREAD_USES_CHRONO
608       template <class Rep, class Period>
try_unlock_shared_and_lock_upgrade_for(const boost::chrono::duration<Rep,Period> & rel_time)609       bool try_unlock_shared_and_lock_upgrade_for(
610           const boost::chrono::duration<Rep, Period>& rel_time)
611       {
612         return try_unlock_shared_and_lock_upgrade_until(chrono::steady_clock::now() + rel_time);
613       }
614       template <class Clock, class Duration>
615       bool try_unlock_shared_and_lock_upgrade_until(
616           const boost::chrono::time_point<Clock, Duration>& abs_time);
617 #endif
618 #endif
619       void unlock_upgrade_and_lock_shared();
620 
621       // Upgrade <-> Exclusive
622 
623       void unlock_upgrade_and_lock();
624       bool try_unlock_upgrade_and_lock();
625 #ifdef BOOST_THREAD_USES_CHRONO
626       template <class Rep, class Period>
try_unlock_upgrade_and_lock_for(const boost::chrono::duration<Rep,Period> & rel_time)627       bool try_unlock_upgrade_and_lock_for(
628           const boost::chrono::duration<Rep, Period>& rel_time)
629       {
630         return try_unlock_upgrade_and_lock_until(chrono::steady_clock::now() + rel_time);
631       }
632       template <class Clock, class Duration>
633       bool try_unlock_upgrade_and_lock_until(
634           const boost::chrono::time_point<Clock, Duration>& abs_time);
635 #endif
636       void unlock_and_lock_upgrade();
637     };
638 
upgrade_mutex()639     inline upgrade_mutex::upgrade_mutex()
640     : gate1_(),
641       gate2_(),
642       state_(0)
643     {
644     }
645 
~upgrade_mutex()646     inline upgrade_mutex::~upgrade_mutex()
647     {
648       boost::lock_guard<mutex_t> _(mut_);
649     }
650 
651     // Exclusive ownership
652 
lock()653     inline void upgrade_mutex::lock()
654     {
655       boost::unique_lock<mutex_t> lk(mut_);
656       gate1_.wait(lk, boost::bind(&upgrade_mutex::no_writer_no_upgrader, boost::ref(*this)));
657       state_ |= write_entered_;
658       gate2_.wait(lk, boost::bind(&upgrade_mutex::no_readers, boost::ref(*this)));
659     }
660 
try_lock()661     inline bool upgrade_mutex::try_lock()
662     {
663       boost::unique_lock<mutex_t> lk(mut_);
664       if (!no_writer_no_upgrader_no_readers())
665       {
666         return false;
667       }
668       state_ = write_entered_;
669       return true;
670     }
671 
672 #ifdef BOOST_THREAD_USES_CHRONO
673     template <class Clock, class Duration>
try_lock_until(const boost::chrono::time_point<Clock,Duration> & abs_time)674     bool upgrade_mutex::try_lock_until(
675         const boost::chrono::time_point<Clock, Duration>& abs_time)
676     {
677       boost::unique_lock<mutex_t> lk(mut_);
678       if (!gate1_.wait_until(lk, abs_time, boost::bind(
679             &upgrade_mutex::no_writer_no_upgrader, boost::ref(*this))))
680       {
681         return false;
682       }
683       state_ |= write_entered_;
684       if (!gate2_.wait_until(lk, abs_time, boost::bind(
685             &upgrade_mutex::no_readers, boost::ref(*this))))
686       {
687         state_ &= ~write_entered_;
688         return false;
689       }
690       return true;
691     }
692 #endif
693 
694 #if defined BOOST_THREAD_USES_DATETIME
695     template<typename T>
timed_lock(T const & abs_or_rel_time)696     bool upgrade_mutex::timed_lock(T const & abs_or_rel_time)
697     {
698       boost::unique_lock<mutex_t> lk(mut_);
699       if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind(
700             &upgrade_mutex::no_writer_no_upgrader, boost::ref(*this))))
701       {
702         return false;
703       }
704       state_ |= write_entered_;
705       if (!gate2_.timed_wait(lk, abs_or_rel_time, boost::bind(
706             &upgrade_mutex::no_readers, boost::ref(*this))))
707       {
708         state_ &= ~write_entered_;
709         return false;
710       }
711       return true;
712     }
713 #endif
714 
unlock()715     inline void upgrade_mutex::unlock()
716     {
717       boost::lock_guard<mutex_t> _(mut_);
718       BOOST_ASSERT(one_writer());
719       BOOST_ASSERT(no_upgrader());
720       BOOST_ASSERT(no_readers());
721       state_ = 0;
722       // notify all since multiple *lock_shared*() calls and a *lock_upgrade*()
723       // call may be able to proceed in response to this notification
724       gate1_.notify_all();
725     }
726 
727     // Shared ownership
728 
lock_shared()729     inline void upgrade_mutex::lock_shared()
730     {
731       boost::unique_lock<mutex_t> lk(mut_);
732       gate1_.wait(lk, boost::bind(&upgrade_mutex::no_writer_no_max_readers, boost::ref(*this)));
733       count_t num_readers = (state_ & n_readers_) + 1;
734       state_ &= ~n_readers_;
735       state_ |= num_readers;
736     }
737 
try_lock_shared()738     inline bool upgrade_mutex::try_lock_shared()
739     {
740       boost::unique_lock<mutex_t> lk(mut_);
741       if (!no_writer_no_max_readers())
742       {
743         return false;
744       }
745       count_t num_readers = (state_ & n_readers_) + 1;
746       state_ &= ~n_readers_;
747       state_ |= num_readers;
748       return true;
749     }
750 
751 #ifdef BOOST_THREAD_USES_CHRONO
752     template <class Clock, class Duration>
try_lock_shared_until(const boost::chrono::time_point<Clock,Duration> & abs_time)753     bool upgrade_mutex::try_lock_shared_until(
754         const boost::chrono::time_point<Clock, Duration>& abs_time)
755     {
756       boost::unique_lock<mutex_t> lk(mut_);
757       if (!gate1_.wait_until(lk, abs_time, boost::bind(
758             &upgrade_mutex::no_writer_no_max_readers, boost::ref(*this))))
759       {
760         return false;
761       }
762       count_t num_readers = (state_ & n_readers_) + 1;
763       state_ &= ~n_readers_;
764       state_ |= num_readers;
765       return true;
766     }
767 #endif
768 
769 #if defined BOOST_THREAD_USES_DATETIME
770     template<typename T>
timed_lock_shared(T const & abs_or_rel_time)771     bool upgrade_mutex::timed_lock_shared(T const & abs_or_rel_time)
772     {
773       boost::unique_lock<mutex_t> lk(mut_);
774       if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind(
775             &upgrade_mutex::no_writer_no_max_readers, boost::ref(*this))))
776       {
777         return false;
778       }
779       count_t num_readers = (state_ & n_readers_) + 1;
780       state_ &= ~n_readers_;
781       state_ |= num_readers;
782       return true;
783     }
784 #endif
785 
unlock_shared()786     inline void upgrade_mutex::unlock_shared()
787     {
788       boost::lock_guard<mutex_t> _(mut_);
789       BOOST_ASSERT(one_or_more_readers());
790       count_t num_readers = (state_ & n_readers_) - 1;
791       state_ &= ~n_readers_;
792       state_ |= num_readers;
793       if (no_writer())
794       {
795         if (num_readers == n_readers_ - 1)
796           gate1_.notify_one();
797       }
798       else
799       {
800         if (num_readers == 0)
801           gate2_.notify_one();
802       }
803     }
804 
805     // Upgrade ownership
806 
lock_upgrade()807     inline void upgrade_mutex::lock_upgrade()
808     {
809       boost::unique_lock<mutex_t> lk(mut_);
810       gate1_.wait(lk, boost::bind(&upgrade_mutex::no_writer_no_upgrader_no_max_readers, boost::ref(*this)));
811       count_t num_readers = (state_ & n_readers_) + 1;
812       state_ &= ~n_readers_;
813       state_ |= upgradable_entered_ | num_readers;
814     }
815 
try_lock_upgrade()816     inline bool upgrade_mutex::try_lock_upgrade()
817     {
818       boost::unique_lock<mutex_t> lk(mut_);
819       if (!no_writer_no_upgrader_no_max_readers())
820       {
821         return false;
822       }
823       count_t num_readers = (state_ & n_readers_) + 1;
824       state_ &= ~n_readers_;
825       state_ |= upgradable_entered_ | num_readers;
826       return true;
827     }
828 
829 #ifdef BOOST_THREAD_USES_CHRONO
830     template <class Clock, class Duration>
try_lock_upgrade_until(const boost::chrono::time_point<Clock,Duration> & abs_time)831     bool upgrade_mutex::try_lock_upgrade_until(
832         const boost::chrono::time_point<Clock, Duration>& abs_time)
833     {
834       boost::unique_lock<mutex_t> lk(mut_);
835       if (!gate1_.wait_until(lk, abs_time, boost::bind(
836             &upgrade_mutex::no_writer_no_upgrader_no_max_readers, boost::ref(*this))))
837       {
838         return false;
839       }
840       count_t num_readers = (state_ & n_readers_) + 1;
841       state_ &= ~n_readers_;
842       state_ |= upgradable_entered_ | num_readers;
843       return true;
844     }
845 #endif
846 
847 #if defined BOOST_THREAD_USES_DATETIME
848     template<typename T>
timed_lock_upgrade(T const & abs_or_rel_time)849     bool upgrade_mutex::timed_lock_upgrade(T const & abs_or_rel_time)
850     {
851       boost::unique_lock<mutex_t> lk(mut_);
852       if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind(
853             &upgrade_mutex::no_writer_no_upgrader_no_max_readers, boost::ref(*this))))
854       {
855         return false;
856       }
857       count_t num_readers = (state_ & n_readers_) + 1;
858       state_ &= ~n_readers_;
859       state_ |= upgradable_entered_ | num_readers;
860       return true;
861     }
862 #endif
863 
unlock_upgrade()864     inline void upgrade_mutex::unlock_upgrade()
865     {
866       boost::lock_guard<mutex_t> _(mut_);
867       BOOST_ASSERT(no_writer());
868       BOOST_ASSERT(one_upgrader());
869       BOOST_ASSERT(one_or_more_readers());
870       count_t num_readers = (state_ & n_readers_) - 1;
871       state_ &= ~(upgradable_entered_ | n_readers_);
872       state_ |= num_readers;
873       // notify all since both a *lock*() and a *lock_shared*() call
874       // may be able to proceed in response to this notification
875       gate1_.notify_all();
876     }
877 
878     // Shared <-> Exclusive
879 
880 #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
try_unlock_shared_and_lock()881     inline bool upgrade_mutex::try_unlock_shared_and_lock()
882     {
883       boost::unique_lock<mutex_t> lk(mut_);
884       BOOST_ASSERT(one_or_more_readers());
885       if (!no_writer_no_upgrader_one_reader())
886       {
887         return false;
888       }
889       state_ = write_entered_;
890       return true;
891     }
892 
893 #ifdef BOOST_THREAD_USES_CHRONO
894     template <class Clock, class Duration>
try_unlock_shared_and_lock_until(const boost::chrono::time_point<Clock,Duration> & abs_time)895     bool upgrade_mutex::try_unlock_shared_and_lock_until(
896         const boost::chrono::time_point<Clock, Duration>& abs_time)
897     {
898       boost::unique_lock<mutex_t> lk(mut_);
899       BOOST_ASSERT(one_or_more_readers());
900       if (!gate1_.wait_until(lk, abs_time, boost::bind(
901             &upgrade_mutex::no_writer_no_upgrader, boost::ref(*this))))
902       {
903         return false;
904       }
905       count_t num_readers = (state_ & n_readers_) - 1;
906       state_ &= ~n_readers_;
907       state_ |= (write_entered_ | num_readers);
908       if (!gate2_.wait_until(lk, abs_time, boost::bind(
909             &upgrade_mutex::no_readers, boost::ref(*this))))
910       {
911         ++num_readers;
912         state_ &= ~(write_entered_ | n_readers_);
913         state_ |= num_readers;
914         return false;
915       }
916       return true;
917     }
918 #endif
919 #endif
920 
unlock_and_lock_shared()921     inline void upgrade_mutex::unlock_and_lock_shared()
922     {
923       boost::lock_guard<mutex_t> _(mut_);
924       BOOST_ASSERT(one_writer());
925       BOOST_ASSERT(no_upgrader());
926       BOOST_ASSERT(no_readers());
927       state_ = 1;
928       // notify all since multiple *lock_shared*() calls and a *lock_upgrade*()
929       // call may be able to proceed in response to this notification
930       gate1_.notify_all();
931     }
932 
933     // Shared <-> Upgrade
934 
935 #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
try_unlock_shared_and_lock_upgrade()936     inline bool upgrade_mutex::try_unlock_shared_and_lock_upgrade()
937     {
938       boost::unique_lock<mutex_t> lk(mut_);
939       BOOST_ASSERT(one_or_more_readers());
940       if (!no_writer_no_upgrader())
941       {
942         return false;
943       }
944       state_ |= upgradable_entered_;
945       return true;
946     }
947 
948 #ifdef BOOST_THREAD_USES_CHRONO
949     template <class Clock, class Duration>
try_unlock_shared_and_lock_upgrade_until(const boost::chrono::time_point<Clock,Duration> & abs_time)950     bool upgrade_mutex::try_unlock_shared_and_lock_upgrade_until(
951         const boost::chrono::time_point<Clock, Duration>& abs_time)
952     {
953       boost::unique_lock<mutex_t> lk(mut_);
954       BOOST_ASSERT(one_or_more_readers());
955       if (!gate1_.wait_until(lk, abs_time, boost::bind(
956             &upgrade_mutex::no_writer_no_upgrader, boost::ref(*this))))
957       {
958         return false;
959       }
960       state_ |= upgradable_entered_;
961       return true;
962     }
963 #endif
964 #endif
965 
unlock_upgrade_and_lock_shared()966     inline void upgrade_mutex::unlock_upgrade_and_lock_shared()
967     {
968       boost::lock_guard<mutex_t> _(mut_);
969       BOOST_ASSERT(no_writer());
970       BOOST_ASSERT(one_upgrader());
971       BOOST_ASSERT(one_or_more_readers());
972       state_ &= ~upgradable_entered_;
973       // notify all since only one *lock*() or *lock_upgrade*() call can win and
974       // proceed in response to this notification, but a *lock_shared*() call may
975       // also be waiting and could steal the notification
976       gate1_.notify_all();
977     }
978 
979     // Upgrade <-> Exclusive
980 
unlock_upgrade_and_lock()981     inline void upgrade_mutex::unlock_upgrade_and_lock()
982     {
983       boost::unique_lock<mutex_t> lk(mut_);
984       BOOST_ASSERT(no_writer());
985       BOOST_ASSERT(one_upgrader());
986       BOOST_ASSERT(one_or_more_readers());
987       count_t num_readers = (state_ & n_readers_) - 1;
988       state_ &= ~(upgradable_entered_ | n_readers_);
989       state_ |= write_entered_ | num_readers;
990       gate2_.wait(lk, boost::bind(&upgrade_mutex::no_readers, boost::ref(*this)));
991     }
992 
try_unlock_upgrade_and_lock()993     inline bool upgrade_mutex::try_unlock_upgrade_and_lock()
994     {
995       boost::unique_lock<mutex_t> lk(mut_);
996       BOOST_ASSERT(no_writer());
997       BOOST_ASSERT(one_upgrader());
998       BOOST_ASSERT(one_or_more_readers());
999       if (!one_reader())
1000       {
1001         return false;
1002       }
1003       state_ = write_entered_;
1004       return true;
1005     }
1006 
1007 #ifdef BOOST_THREAD_USES_CHRONO
1008     template <class Clock, class Duration>
try_unlock_upgrade_and_lock_until(const boost::chrono::time_point<Clock,Duration> & abs_time)1009     bool upgrade_mutex::try_unlock_upgrade_and_lock_until(
1010         const boost::chrono::time_point<Clock, Duration>& abs_time)
1011     {
1012       boost::unique_lock<mutex_t> lk(mut_);
1013       BOOST_ASSERT(no_writer());
1014       BOOST_ASSERT(one_upgrader());
1015       BOOST_ASSERT(one_or_more_readers());
1016       count_t num_readers = (state_ & n_readers_) - 1;
1017       state_ &= ~(upgradable_entered_ | n_readers_);
1018       state_ |= (write_entered_ | num_readers);
1019       if (!gate2_.wait_until(lk, abs_time, boost::bind(
1020             &upgrade_mutex::no_readers, boost::ref(*this))))
1021       {
1022         ++num_readers;
1023         state_ &= ~(write_entered_ | n_readers_);
1024         state_ |= (upgradable_entered_ | num_readers);
1025         return false;
1026       }
1027       return true;
1028     }
1029 #endif
1030 
unlock_and_lock_upgrade()1031     inline void upgrade_mutex::unlock_and_lock_upgrade()
1032     {
1033       boost::lock_guard<mutex_t> _(mut_);
1034       BOOST_ASSERT(one_writer());
1035       BOOST_ASSERT(no_upgrader());
1036       BOOST_ASSERT(no_readers());
1037       state_ = upgradable_entered_ | 1;
1038       // notify all since multiple *lock_shared*() calls may be able
1039       // to proceed in response to this notification
1040       gate1_.notify_all();
1041     }
1042 
1043   }  // thread_v2
1044 }  // boost
1045 
1046 namespace boost {
1047   //using thread_v2::shared_mutex;
1048   using thread_v2::upgrade_mutex;
1049   typedef thread_v2::upgrade_mutex shared_mutex;
1050 }
1051 
1052 #endif
1053