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