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 
21 enum {reading, writing};
22 int state = reading;
23 
24 #if 1
25 
26 boost::mutex&
cout_mut()27 cout_mut()
28 {
29     static boost::mutex m;
30     return m;
31 }
32 
33 void
print(const char * tag,unsigned count,char ch)34 print(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 
42 boost::recursive_mutex&
cout_mut()43 cout_mut()
44 {
45     static boost::recursive_mutex m;
46     return m;
47 }
48 
print()49 void print() {}
50 
51 template <class A0, class ...Args>
52 void
print(const A0 & a0,const Args &...args)53 print(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 
62 template <class A0, class A1, class A2>
63 void
print(const A0 &,const A1 & a1,const A2 &)64 print(const A0&, const A1& a1, const A2&)
65 {
66     assert(a1 > 10000);
67 }
68 
69 #endif
70 
71 namespace S
72 {
73 
74 boost::shared_mutex mut;
75 
reader()76 void 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("reader = ", count, '\n');
89 }
90 
writer()91 void 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("writer = ", count, '\n');
106 }
107 
try_reader()108 void 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("try_reader = ", count, '\n');
123 }
124 
try_writer()125 void 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("try_writer = ", count, '\n');
142 }
143 
try_for_reader()144 void 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(boost::chrono::microseconds(5)))
152         {
153             assert(state == reading);
154             ++count;
155             mut.unlock_shared();
156         }
157     }
158     print("try_for_reader = ", count, '\n');
159 }
160 
try_for_writer()161 void 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(boost::chrono::microseconds(5)))
169         {
170             state = writing;
171             assert(state == writing);
172             state = reading;
173             ++count;
174             mut.unlock();
175         }
176     }
177     print("try_for_writer = ", count, '\n');
178 }
179 
180 void
test_shared_mutex()181 test_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 
215 namespace U
216 {
217 
218 boost::upgrade_mutex mut;
219 
reader()220 void 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("reader = ", count, '\n');
233 }
234 
writer()235 void 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("writer = ", count, '\n');
250 }
251 
try_reader()252 void 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("try_reader = ", count, '\n');
267 }
268 
try_writer()269 void 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("try_writer = ", count, '\n');
286 }
287 
try_for_reader()288 void 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(boost::chrono::microseconds(5)))
296         {
297             assert(state == reading);
298             ++count;
299             mut.unlock_shared();
300         }
301     }
302     print("try_for_reader = ", count, '\n');
303 }
304 
try_for_writer()305 void 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(boost::chrono::microseconds(5)))
313         {
314             state = writing;
315             assert(state == writing);
316             state = reading;
317             ++count;
318             mut.unlock();
319         }
320     }
321     print("try_for_writer = ", count, '\n');
322 }
323 
upgradable()324 void 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("upgradable = ", count, '\n');
337 }
338 
try_upgradable()339 void 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("try_upgradable = ", count, '\n');
354 }
355 
try_for_upgradable()356 void 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(boost::chrono::microseconds(5)))
364         {
365             assert(state == reading);
366             ++count;
367             mut.unlock_upgrade();
368         }
369     }
370     print("try_for_upgradable = ", count, '\n');
371 }
372 
clockwise()373 void 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("clockwise = ", count, '\n');
407 }
408 
counter_clockwise()409 void 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("counter_clockwise = ", count, '\n');
429 }
430 
try_clockwise()431 void 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("try_clockwise = ", count, '\n');
467 }
468 
try_for_clockwise()469 void 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(boost::chrono::microseconds(5)))
477         {
478             assert(state == reading);
479             if (mut.try_unlock_shared_and_lock_for(boost::chrono::microseconds(5)))
480             {
481                 state = writing;
482             }
483             else if (mut.try_unlock_shared_and_lock_upgrade_for(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("try_for_clockwise = ", count, '\n');
505 }
506 
try_counter_clockwise()507 void 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("try_counter_clockwise = ", count, '\n');
535 }
536 
try_for_counter_clockwise()537 void 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(boost::chrono::microseconds(5)))
545         {
546             assert(state == reading);
547             if (mut.try_unlock_upgrade_and_lock_for(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("try_for_counter_clockwise = ", count, '\n');
565 }
566 
567 void
test_upgrade_mutex()568 test_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 
657 namespace Assignment
658 {
659 
660 class 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 
670 public:
671 
A(const A & a)672     A(const A& a)
673     {
674         SharedLock _(a.mut_);
675         data_ = a.data_;
676     }
677 
operator =(const A & a)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(this_lock, that_lock);
685             data_ = a.data_;
686         }
687         return *this;
688     }
689 
swap(A & a)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(this_lock, that_lock);
695         data_.swap(a.data_);
696     }
697 
average(A & a)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(this_lock, 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(this_lock));
711         Lock that_lock(boost::move(share_that_lock));
712         a.data_ = data_;
713     }
714 };
715 
716 }  // Assignment
717 
temp()718 void 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 
main()727 int 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