1// Copyright (C) 2012 Vicente J. Botet Escriba
2//
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6#define BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
7#define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION
8#define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
9
10#include <iostream>
11#include <boost/thread/mutex.hpp>
12#include <boost/thread/shared_mutex.hpp>
13#include <boost/thread/lock_algorithms.hpp>
14#include <boost/thread/thread_only.hpp>
15#include <vector>
16
17#if defined BOOST_THREAD_USES_CHRONO
18#include <boost/chrono/chrono_io.hpp>
19
20
21enum {reading, writing};
22int state = reading;
23
24#if 1
25
26boost::mutex&
27cout_mut()
28{
29 static boost::mutex m;
30 return m;
31}
32
33void
34print(const char* tag, unsigned count, char ch)
35{
36 boost::lock_guard<boost::mutex> _(cout_mut());
37 std::cout << tag << count << ch;
38}
39
40#elif 0
41
42boost::recursive_mutex&
43cout_mut()
44{
45 static boost::recursive_mutex m;
46 return m;
47}
48
49void print() {}
50
51template <class A0, class ...Args>
52void
53print(const A0& a0, const Args& ...args)
54{
55 boost::lock_guard<boost::recursive_mutex> _(cout_mut());
56 std::cout << a0;
57 print(args...);
58}
59
60#else
61
62template <class A0, class A1, class A2>
63void
64print(const A0&, const A1& a1, const A2&)
65{
66 assert(a1 > 10000);
67}
68
69#endif
70
71namespace S
72{
73
74boost::shared_mutex mut;
75
76void reader()
77{
78 typedef boost::chrono::steady_clock Clock;
79 unsigned count = 0;
80 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
81 while (Clock::now() < until)
82 {
83 mut.lock_shared();
84 assert(state == reading);
85 ++count;
86 mut.unlock_shared();
87 }
88 print(tag: "reader = ", count, ch: '\n');
89}
90
91void writer()
92{
93 typedef boost::chrono::steady_clock Clock;
94 unsigned count = 0;
95 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
96 while (Clock::now() < until)
97 {
98 mut.lock();
99 state = writing;
100 assert(state == writing);
101 state = reading;
102 ++count;
103 mut.unlock();
104 }
105 print(tag: "writer = ", count, ch: '\n');
106}
107
108void try_reader()
109{
110 typedef boost::chrono::steady_clock Clock;
111 unsigned count = 0;
112 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
113 while (Clock::now() < until)
114 {
115 if (mut.try_lock_shared())
116 {
117 assert(state == reading);
118 ++count;
119 mut.unlock_shared();
120 }
121 }
122 print(tag: "try_reader = ", count, ch: '\n');
123}
124
125void try_writer()
126{
127 typedef boost::chrono::steady_clock Clock;
128 unsigned count = 0;
129 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
130 while (Clock::now() < until)
131 {
132 if (mut.try_lock())
133 {
134 state = writing;
135 assert(state == writing);
136 state = reading;
137 ++count;
138 mut.unlock();
139 }
140 }
141 print(tag: "try_writer = ", count, ch: '\n');
142}
143
144void try_for_reader()
145{
146 typedef boost::chrono::steady_clock Clock;
147 unsigned count = 0;
148 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
149 while (Clock::now() < until)
150 {
151 if (mut.try_lock_shared_for(rel_time: boost::chrono::microseconds(5)))
152 {
153 assert(state == reading);
154 ++count;
155 mut.unlock_shared();
156 }
157 }
158 print(tag: "try_for_reader = ", count, ch: '\n');
159}
160
161void try_for_writer()
162{
163 typedef boost::chrono::steady_clock Clock;
164 unsigned count = 0;
165 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
166 while (Clock::now() < until)
167 {
168 if (mut.try_lock_for(rel_time: boost::chrono::microseconds(5)))
169 {
170 state = writing;
171 assert(state == writing);
172 state = reading;
173 ++count;
174 mut.unlock();
175 }
176 }
177 print(tag: "try_for_writer = ", count, ch: '\n');
178}
179
180void
181test_shared_mutex()
182{
183 std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
184 {
185 boost::thread t1(reader);
186 boost::thread t2(writer);
187 boost::thread t3(reader);
188 t1.join();
189 t2.join();
190 t3.join();
191 }
192 std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
193 {
194 boost::thread t1(try_reader);
195 boost::thread t2(try_writer);
196 boost::thread t3(try_reader);
197 t1.join();
198 t2.join();
199 t3.join();
200 }
201 std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
202 {
203 boost::thread t1(try_for_reader);
204 boost::thread t2(try_for_writer);
205 boost::thread t3(try_for_reader);
206 t1.join();
207 t2.join();
208 t3.join();
209 }
210 std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
211}
212
213}
214
215namespace U
216{
217
218boost::upgrade_mutex mut;
219
220void reader()
221{
222 typedef boost::chrono::steady_clock Clock;
223 unsigned count = 0;
224 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
225 while (Clock::now() < until)
226 {
227 mut.lock_shared();
228 assert(state == reading);
229 ++count;
230 mut.unlock_shared();
231 }
232 print(tag: "reader = ", count, ch: '\n');
233}
234
235void writer()
236{
237 typedef boost::chrono::steady_clock Clock;
238 unsigned count = 0;
239 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
240 while (Clock::now() < until)
241 {
242 mut.lock();
243 state = writing;
244 assert(state == writing);
245 state = reading;
246 ++count;
247 mut.unlock();
248 }
249 print(tag: "writer = ", count, ch: '\n');
250}
251
252void try_reader()
253{
254 typedef boost::chrono::steady_clock Clock;
255 unsigned count = 0;
256 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
257 while (Clock::now() < until)
258 {
259 if (mut.try_lock_shared())
260 {
261 assert(state == reading);
262 ++count;
263 mut.unlock_shared();
264 }
265 }
266 print(tag: "try_reader = ", count, ch: '\n');
267}
268
269void try_writer()
270{
271 typedef boost::chrono::steady_clock Clock;
272 unsigned count = 0;
273 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
274 while (Clock::now() < until)
275 {
276 if (mut.try_lock())
277 {
278 state = writing;
279 assert(state == writing);
280 state = reading;
281 ++count;
282 mut.unlock();
283 }
284 }
285 print(tag: "try_writer = ", count, ch: '\n');
286}
287
288void try_for_reader()
289{
290 typedef boost::chrono::steady_clock Clock;
291 unsigned count = 0;
292 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
293 while (Clock::now() < until)
294 {
295 if (mut.try_lock_shared_for(rel_time: boost::chrono::microseconds(5)))
296 {
297 assert(state == reading);
298 ++count;
299 mut.unlock_shared();
300 }
301 }
302 print(tag: "try_for_reader = ", count, ch: '\n');
303}
304
305void try_for_writer()
306{
307 typedef boost::chrono::steady_clock Clock;
308 unsigned count = 0;
309 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
310 while (Clock::now() < until)
311 {
312 if (mut.try_lock_for(rel_time: boost::chrono::microseconds(5)))
313 {
314 state = writing;
315 assert(state == writing);
316 state = reading;
317 ++count;
318 mut.unlock();
319 }
320 }
321 print(tag: "try_for_writer = ", count, ch: '\n');
322}
323
324void upgradable()
325{
326 typedef boost::chrono::steady_clock Clock;
327 unsigned count = 0;
328 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
329 while (Clock::now() < until)
330 {
331 mut.lock_upgrade();
332 assert(state == reading);
333 ++count;
334 mut.unlock_upgrade();
335 }
336 print(tag: "upgradable = ", count, ch: '\n');
337}
338
339void try_upgradable()
340{
341 typedef boost::chrono::steady_clock Clock;
342 unsigned count = 0;
343 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
344 while (Clock::now() < until)
345 {
346 if (mut.try_lock_upgrade())
347 {
348 assert(state == reading);
349 ++count;
350 mut.unlock_upgrade();
351 }
352 }
353 print(tag: "try_upgradable = ", count, ch: '\n');
354}
355
356void try_for_upgradable()
357{
358 typedef boost::chrono::steady_clock Clock;
359 unsigned count = 0;
360 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
361 while (Clock::now() < until)
362 {
363 if (mut.try_lock_upgrade_for(rel_time: boost::chrono::microseconds(5)))
364 {
365 assert(state == reading);
366 ++count;
367 mut.unlock_upgrade();
368 }
369 }
370 print(tag: "try_for_upgradable = ", count, ch: '\n');
371}
372
373void clockwise()
374{
375 typedef boost::chrono::steady_clock Clock;
376 unsigned count = 0;
377 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
378 while (Clock::now() < until)
379 {
380 mut.lock_shared();
381 assert(state == reading);
382 if (mut.try_unlock_shared_and_lock())
383 {
384 state = writing;
385 }
386 else if (mut.try_unlock_shared_and_lock_upgrade())
387 {
388 assert(state == reading);
389 mut.unlock_upgrade_and_lock();
390 state = writing;
391 }
392 else
393 {
394 mut.unlock_shared();
395 continue;
396 }
397 assert(state == writing);
398 state = reading;
399 mut.unlock_and_lock_upgrade();
400 assert(state == reading);
401 mut.unlock_upgrade_and_lock_shared();
402 assert(state == reading);
403 mut.unlock_shared();
404 ++count;
405 }
406 print(tag: "clockwise = ", count, ch: '\n');
407}
408
409void counter_clockwise()
410{
411 typedef boost::chrono::steady_clock Clock;
412 unsigned count = 0;
413 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
414 while (Clock::now() < until)
415 {
416 mut.lock_upgrade();
417 assert(state == reading);
418 mut.unlock_upgrade_and_lock();
419 assert(state == reading);
420 state = writing;
421 assert(state == writing);
422 state = reading;
423 mut.unlock_and_lock_shared();
424 assert(state == reading);
425 mut.unlock_shared();
426 ++count;
427 }
428 print(tag: "counter_clockwise = ", count, ch: '\n');
429}
430
431void try_clockwise()
432{
433 typedef boost::chrono::steady_clock Clock;
434 unsigned count = 0;
435 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
436 while (Clock::now() < until)
437 {
438 if (mut.try_lock_shared())
439 {
440 assert(state == reading);
441 if (mut.try_unlock_shared_and_lock())
442 {
443 state = writing;
444 }
445 else if (mut.try_unlock_shared_and_lock_upgrade())
446 {
447 assert(state == reading);
448 mut.unlock_upgrade_and_lock();
449 state = writing;
450 }
451 else
452 {
453 mut.unlock_shared();
454 continue;
455 }
456 assert(state == writing);
457 state = reading;
458 mut.unlock_and_lock_upgrade();
459 assert(state == reading);
460 mut.unlock_upgrade_and_lock_shared();
461 assert(state == reading);
462 mut.unlock_shared();
463 ++count;
464 }
465 }
466 print(tag: "try_clockwise = ", count, ch: '\n');
467}
468
469void try_for_clockwise()
470{
471 typedef boost::chrono::steady_clock Clock;
472 unsigned count = 0;
473 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
474 while (Clock::now() < until)
475 {
476 if (mut.try_lock_shared_for(rel_time: boost::chrono::microseconds(5)))
477 {
478 assert(state == reading);
479 if (mut.try_unlock_shared_and_lock_for(rel_time: boost::chrono::microseconds(5)))
480 {
481 state = writing;
482 }
483 else if (mut.try_unlock_shared_and_lock_upgrade_for(rel_time: boost::chrono::microseconds(5)))
484 {
485 assert(state == reading);
486 mut.unlock_upgrade_and_lock();
487 state = writing;
488 }
489 else
490 {
491 mut.unlock_shared();
492 continue;
493 }
494 assert(state == writing);
495 state = reading;
496 mut.unlock_and_lock_upgrade();
497 assert(state == reading);
498 mut.unlock_upgrade_and_lock_shared();
499 assert(state == reading);
500 mut.unlock_shared();
501 ++count;
502 }
503 }
504 print(tag: "try_for_clockwise = ", count, ch: '\n');
505}
506
507void try_counter_clockwise()
508{
509 typedef boost::chrono::steady_clock Clock;
510 unsigned count = 0;
511 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
512 while (Clock::now() < until)
513 {
514 if (mut.try_lock_upgrade())
515 {
516 assert(state == reading);
517 if (mut.try_unlock_upgrade_and_lock())
518 {
519 assert(state == reading);
520 state = writing;
521 assert(state == writing);
522 state = reading;
523 mut.unlock_and_lock_shared();
524 assert(state == reading);
525 mut.unlock_shared();
526 ++count;
527 }
528 else
529 {
530 mut.unlock_upgrade();
531 }
532 }
533 }
534 print(tag: "try_counter_clockwise = ", count, ch: '\n');
535}
536
537void try_for_counter_clockwise()
538{
539 typedef boost::chrono::steady_clock Clock;
540 unsigned count = 0;
541 Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
542 while (Clock::now() < until)
543 {
544 if (mut.try_lock_upgrade_for(rel_time: boost::chrono::microseconds(5)))
545 {
546 assert(state == reading);
547 if (mut.try_unlock_upgrade_and_lock_for(rel_time: boost::chrono::microseconds(5)))
548 {
549 assert(state == reading);
550 state = writing;
551 assert(state == writing);
552 state = reading;
553 mut.unlock_and_lock_shared();
554 assert(state == reading);
555 mut.unlock_shared();
556 ++count;
557 }
558 else
559 {
560 mut.unlock_upgrade();
561 }
562 }
563 }
564 print(tag: "try_for_counter_clockwise = ", count, ch: '\n');
565}
566
567void
568test_upgrade_mutex()
569{
570 std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
571 {
572 boost::thread t1(reader);
573 boost::thread t2(writer);
574 boost::thread t3(reader);
575 t1.join();
576 t2.join();
577 t3.join();
578 }
579 std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
580 {
581 boost::thread t1(try_reader);
582 boost::thread t2(try_writer);
583 boost::thread t3(try_reader);
584 t1.join();
585 t2.join();
586 t3.join();
587 }
588 std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
589 {
590 boost::thread t1(try_for_reader);
591 boost::thread t2(try_for_writer);
592 boost::thread t3(try_for_reader);
593 t1.join();
594 t2.join();
595 t3.join();
596 }
597 std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
598 {
599 boost::thread t1(reader);
600 boost::thread t2(writer);
601 boost::thread t3(upgradable);
602 t1.join();
603 t2.join();
604 t3.join();
605 }
606 std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
607 {
608 boost::thread t1(reader);
609 boost::thread t2(writer);
610 boost::thread t3(try_upgradable);
611 t1.join();
612 t2.join();
613 t3.join();
614 }
615 std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
616 {
617 boost::thread t1(reader);
618 boost::thread t2(writer);
619 boost::thread t3(try_for_upgradable);
620 t1.join();
621 t2.join();
622 t3.join();
623 }
624 std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
625 {
626 state = reading;
627 boost::thread t1(clockwise);
628 boost::thread t2(counter_clockwise);
629 boost::thread t3(clockwise);
630 boost::thread t4(counter_clockwise);
631 t1.join();
632 t2.join();
633 t3.join();
634 t4.join();
635 }
636 std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
637 {
638 state = reading;
639 boost::thread t1(try_clockwise);
640 boost::thread t2(try_counter_clockwise);
641 t1.join();
642 t2.join();
643 }
644 std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
645// {
646// state = reading;
647// boost::thread t1(try_for_clockwise);
648// boost::thread t2(try_for_counter_clockwise);
649// t1.join();
650// t2.join();
651// }
652// std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
653}
654
655}
656
657namespace Assignment
658{
659
660class A
661{
662 typedef boost::upgrade_mutex mutex_type;
663 typedef boost::shared_lock<mutex_type> SharedLock;
664 typedef boost::upgrade_lock<mutex_type> UpgradeLock;
665 typedef boost::unique_lock<mutex_type> Lock;
666
667 mutable mutex_type mut_;
668 std::vector<double> data_;
669
670public:
671
672 A(const A& a)
673 {
674 SharedLock _(a.mut_);
675 data_ = a.data_;
676 }
677
678 A& operator=(const A& a)
679 {
680 if (this != &a)
681 {
682 Lock this_lock(mut_, boost::defer_lock);
683 SharedLock that_lock(a.mut_, boost::defer_lock);
684 boost::lock(m1&: this_lock, m2&: that_lock);
685 data_ = a.data_;
686 }
687 return *this;
688 }
689
690 void swap(A& a)
691 {
692 Lock this_lock(mut_, boost::defer_lock);
693 Lock that_lock(a.mut_, boost::defer_lock);
694 boost::lock(m1&: this_lock, m2&: that_lock);
695 data_.swap(x&: a.data_);
696 }
697
698 void average(A& a)
699 {
700 assert(data_.size() == a.data_.size());
701 assert(this != &a);
702
703 Lock this_lock(mut_, boost::defer_lock);
704 UpgradeLock share_that_lock(a.mut_, boost::defer_lock);
705 boost::lock(m1&: this_lock, m2&: share_that_lock);
706
707 for (unsigned i = 0; i < data_.size(); ++i)
708 data_[i] = (data_[i] + a.data_[i]) / 2;
709
710 SharedLock share_this_lock(boost::move(t&: this_lock));
711 Lock that_lock(boost::move(t&: share_that_lock));
712 a.data_ = data_;
713 }
714};
715
716} // Assignment
717
718void temp()
719{
720 using namespace boost;
721 static upgrade_mutex mut;
722 unique_lock<upgrade_mutex> ul(mut);
723 shared_lock<upgrade_mutex> sl;
724 sl = BOOST_THREAD_MAKE_RV_REF(shared_lock<upgrade_mutex>(boost::move(ul)));
725}
726
727int main()
728{
729 std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
730 typedef boost::chrono::high_resolution_clock Clock;
731 typedef boost::chrono::duration<double> sec;
732 Clock::time_point t0 = Clock::now();
733
734 std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
735 S::test_shared_mutex();
736 std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
737 U::test_upgrade_mutex();
738 std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
739 Clock::time_point t1 = Clock::now();
740 std::cout << sec(t1 - t0) << '\n';
741 return 0;
742}
743
744#else
745#error "This platform doesn't support Boost.Chrono"
746#endif
747

source code of boost/libs/thread/example/shared_mutex.cpp