fork download
  1. #include <iostream>
  2. #include <memory>
  3. #include <queue>
  4. #include <future>
  5.  
  6. #include <iostream>
  7. #include <mutex>
  8.  
  9. class RWLocker final
  10. {
  11. mutable std::mutex general_lock_;
  12. mutable std::mutex write_lock_;
  13. mutable std::mutex read_lock_;
  14.  
  15. mutable std::size_t number_of_readers_ = 0;
  16.  
  17. RWLocker (const RWLocker &) = delete;
  18. RWLocker & operator= (const RWLocker &) = delete;
  19.  
  20. public:
  21. RWLocker () = default;
  22.  
  23. //Only read and write abstractions can work with RWLocker
  24. friend class ReadGuard;
  25. friend class WriteGuard;
  26. };
  27.  
  28. class WriteGuard final
  29. {
  30. const RWLocker & locker_;
  31.  
  32. WriteGuard (const WriteGuard &) = delete;
  33. WriteGuard & operator= (const WriteGuard &) = delete;
  34.  
  35. public:
  36.  
  37. //Strong exception guarantee
  38. explicit WriteGuard (const RWLocker & input_lock) :
  39. locker_ { input_lock }
  40. {
  41. locker_.general_lock_.lock ();
  42. locker_.write_lock_.lock ();
  43. locker_.general_lock_.unlock ();
  44. }
  45.  
  46. ~WriteGuard ()
  47. {
  48. //Anyway UB if unlock fails
  49. locker_.write_lock_.unlock ();
  50. }
  51. };
  52.  
  53. class ReadGuard final
  54. {
  55. const RWLocker & locker_;
  56.  
  57. ReadGuard (const ReadGuard &) = delete;
  58. ReadGuard & operator= (const ReadGuard &) = delete;
  59.  
  60. public:
  61.  
  62. //Strong exception guarantee
  63. explicit ReadGuard (const RWLocker & input_lock) :
  64. locker_ { input_lock }
  65. {
  66. locker_.general_lock_.lock ();
  67. locker_.read_lock_.lock ();
  68. locker_.general_lock_.unlock ();
  69.  
  70. if (0 < ++locker_.number_of_readers_)
  71. locker_.write_lock_.lock ();
  72.  
  73. locker_.read_lock_.unlock ();
  74. }
  75.  
  76. ~ReadGuard ()
  77. {
  78. //Anyway UB if unlock fails
  79. if (1 > --locker_.number_of_readers_)
  80. locker_.write_lock_.unlock ();
  81.  
  82. locker_.read_lock_.unlock ();
  83. }
  84. };
  85.  
  86. template<typename T>
  87. std::chrono::milliseconds measure_execution_time(T _t)
  88. {
  89. std::chrono::steady_clock clock;
  90. auto tp_begin = clock.now();
  91. _t();
  92. auto tp_end = clock.now();
  93. auto execution_time =
  94. std::chrono::duration_cast<std::chrono::milliseconds>(
  95. tp_end.time_since_epoch() - tp_begin.time_since_epoch()
  96. );
  97. return execution_time;
  98. }
  99.  
  100. int main()
  101. {
  102. const int n = 10000000;
  103. {
  104. RWLocker locker;
  105. auto time = measure_execution_time([n, &locker](){
  106. long c = 0;
  107. for (int i = 0; i< n; ++i)
  108. {
  109. ReadGuard guard(locker);
  110. c += i;
  111. }
  112. });
  113.  
  114. std::cout << "Yoba mutex: " << time.count() << std::endl;
  115. }
  116.  
  117. {
  118. std::mutex m;
  119. auto time = measure_execution_time([n, &m](){
  120. long c = 0;
  121. for (int i = 0; i< n; ++i)
  122. {
  123. std::lock_guard<std::mutex> lock(m);
  124. c += i;
  125. }
  126. });
  127.  
  128. std::cout << "Mutex: " << time.count() << std::endl;
  129. }
  130.  
  131.  
  132. return 0;
  133. }
  134.  
  135.  
Runtime error #stdin #stdout 0s 3464KB
stdin
Standard input is empty
stdout
Standard output is empty