Advertisement
Chris_M_Thomasson

my read/write mutex vs Windows SRW

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