Advertisement
Chris_M_Thomasson

crude read/write mutex benchmark...

Feb 14th, 2019
605
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.73 KB | None | 0 0
  1. /* Simple, crude read/write mutex test
  2. by: Chris M. Thomasson
  3. __________________________________________*/
  4.  
  5.  
  6.  
  7. #include <thread>
  8. #include <atomic>
  9. #include <shared_mutex>
  10. #include <condition_variable>
  11. #include <iostream>
  12. #include <functional>
  13. #include <cassert>
  14. #include <cstdlib>
  15. #include <ctime>
  16. #include <climits>
  17.  
  18.  
  19. #define THREADS 16UL
  20. #define ITERS 10000000UL
  21. #define COUNT (THREADS * ITERS)
  22.  
  23.  
  24. // undefine to test std::shared_mutex
  25. #define CT_TEST_FAST_MUTEX 1
  26.  
  27.  
  28. // bare bones mutex/condvar based semaphore
  29. struct ct_slow_semaphore
  30. {
  31. unsigned long m_state;
  32. std::mutex m_mutex;
  33. std::condition_variable m_cond;
  34.  
  35. ct_slow_semaphore(unsigned long state) : m_state(state) {}
  36.  
  37. void inc()
  38. {
  39. {
  40. std::unique_lock<std::mutex> lock(m_mutex);
  41. ++m_state;
  42. }
  43.  
  44. m_cond.notify_one();
  45. }
  46.  
  47. void add(unsigned long addend)
  48. {
  49. {
  50. std::unique_lock<std::mutex> lock(m_mutex);
  51. m_state += addend;
  52. }
  53.  
  54. m_cond.notify_all();
  55. }
  56.  
  57. void dec()
  58. {
  59. std::unique_lock<std::mutex> lock(m_mutex);
  60. while (m_state == 0) m_cond.wait(lock);
  61. --m_state;
  62. }
  63. };
  64.  
  65.  
  66.  
  67.  
  68. // bin-sema
  69. struct ct_auto_reset_event
  70. {
  71. bool m_state;
  72. std::mutex m_mutex;
  73. std::condition_variable m_cond;
  74.  
  75. ct_auto_reset_event() : m_state(false) {}
  76.  
  77. void signal()
  78. {
  79. std::unique_lock<std::mutex> lock(m_mutex);
  80. m_state = true;
  81. m_cond.notify_one();
  82. }
  83.  
  84. void wait()
  85. {
  86. std::unique_lock<std::mutex> lock(m_mutex);
  87. while (m_state == false) m_cond.wait(lock);
  88. m_state = false; // auto-reset
  89. }
  90. };
  91.  
  92.  
  93. // just a layer over an auto-reset event
  94. struct ct_fast_mutex
  95. {
  96. std::atomic<unsigned int> m_state;
  97. ct_auto_reset_event m_waitset;
  98.  
  99. ct_fast_mutex() : m_state(0) {}
  100.  
  101. void lock()
  102. {
  103. if (m_state.exchange(1, std::memory_order_acquire))
  104. {
  105. while (m_state.exchange(2, std::memory_order_acquire))
  106. {
  107. m_waitset.wait();
  108. }
  109. }
  110. }
  111.  
  112. void unlock()
  113. {
  114. if (m_state.exchange(0, std::memory_order_release) == 2)
  115. {
  116. m_waitset.signal();
  117. }
  118. }
  119. };
  120.  
  121.  
  122.  
  123. // Chris M. Thomassons Experimental Read/Write Mutex
  124. // Yeah, it is pretty damn fat wrt the state, however
  125. // it has some interesting properties...
  126. // The state can be compressed a bit...
  127. // btw, it has no loops...
  128. // Take a look at the lock_shared and unlock_shared functions
  129.  
  130. #define RWMUTEX_COUNT_MAX LONG_MAX
  131.  
  132. struct ct_rwmutex
  133. {
  134. // shared state
  135. std::atomic<long> m_wrstate;
  136. std::atomic<long> m_count;
  137. std::atomic<long> m_rdwake;
  138.  
  139. ct_slow_semaphore m_rdwset;
  140. ct_slow_semaphore m_wrwset;
  141. ct_fast_mutex m_wrlock;
  142.  
  143.  
  144. ct_rwmutex() :
  145. m_wrstate(1),
  146. m_count(RWMUTEX_COUNT_MAX),
  147. m_rdwake(0),
  148. m_rdwset(0),
  149. m_wrwset(0) {
  150. }
  151.  
  152.  
  153. // READ, pretty slim...
  154. void lock_shared()
  155. {
  156. if (m_count.fetch_add(-1, std::memory_order_acquire) < 1)
  157. {
  158. m_rdwset.dec();
  159. }
  160. }
  161.  
  162. void unlock_shared()
  163. {
  164. if (m_count.fetch_add(1, std::memory_order_release) < 0)
  165. {
  166. if (m_rdwake.fetch_add(-1, std::memory_order_acq_rel) == 1)
  167. {
  168. m_wrwset.inc();
  169. }
  170. }
  171. }
  172.  
  173.  
  174. // WRITE, more hefty
  175. void lock()
  176. {
  177. m_wrlock.lock();
  178.  
  179. long count = m_count.fetch_add(-RWMUTEX_COUNT_MAX, std::memory_order_acquire);
  180.  
  181. if (count < RWMUTEX_COUNT_MAX)
  182. {
  183. long rdwake = m_rdwake.fetch_add(RWMUTEX_COUNT_MAX - count, std::memory_order_acquire);
  184.  
  185. if (rdwake + RWMUTEX_COUNT_MAX - count)
  186. {
  187. m_wrwset.dec();
  188. }
  189. }
  190. }
  191.  
  192. // write unlock
  193. void unlock()
  194. {
  195. long count = m_count.fetch_add(RWMUTEX_COUNT_MAX, std::memory_order_release);
  196.  
  197. if (count < 0)
  198. {
  199. m_rdwset.add(-count);
  200. }
  201.  
  202. m_wrlock.unlock();
  203. }
  204. };
  205.  
  206.  
  207. struct ct_shared
  208. {
  209. std::atomic<unsigned long> m_state;
  210.  
  211. #if defined (CT_TEST_FAST_MUTEX)
  212. ct_rwmutex m_std_rwmutex;
  213. #else
  214. std::shared_mutex m_std_rwmutex;
  215. #endif
  216.  
  217. ct_shared() : m_state(0) {}
  218. };
  219.  
  220.  
  221. void ct_thread(ct_shared& shared, std::size_t index)
  222. {
  223. for (unsigned int i = 0; i < ITERS; ++i)
  224. {
  225.  
  226. shared.m_std_rwmutex.lock();
  227. if (i % 256 == 0) std::this_thread::yield();
  228. shared.m_state += 1;
  229. shared.m_std_rwmutex.unlock();
  230.  
  231.  
  232. shared.m_std_rwmutex.lock_shared();
  233. if (i % 512 == 0) std::this_thread::yield();
  234. //shared.m_state += 1;
  235. shared.m_std_rwmutex.unlock_shared();
  236.  
  237. }
  238. }
  239.  
  240.  
  241. int main()
  242. {
  243. ct_shared shared;
  244.  
  245. std::cout << "Testing: ";
  246.  
  247. #if defined (CT_TEST_FAST_MUTEX)
  248. std::cout << "Chris M. Thomasson's Experimental Read/Write Mutex\n\n";
  249. #else
  250. std::cout << "std::shared_mutex\n\n";
  251. #endif
  252.  
  253. {
  254. std::thread threads[THREADS];
  255.  
  256. std::clock_t start = std::clock();
  257.  
  258. for (std::size_t i = 0; i < THREADS; ++i)
  259. {
  260. threads[i] = std::thread(ct_thread, std::ref(shared), i);
  261. }
  262.  
  263. for (std::size_t i = 0; i < THREADS; ++i)
  264. {
  265. threads[i].join();
  266. }
  267.  
  268. std::clock_t diff = clock() - start;
  269.  
  270. unsigned long msec = diff * 1000 / CLOCKS_PER_SEC;
  271.  
  272. std::cout << "msec = " << msec << "\n";
  273. }
  274.  
  275. std::cout << "shared.m_state = " << shared.m_state << "\n";
  276. std::cout << "\n\nFin!\n";
  277.  
  278. assert(shared.m_state == COUNT);
  279.  
  280. return 0;
  281. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement