Advertisement
Guest User

Untitled

a guest
Jan 22nd, 2017
124
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.53 KB | None | 0 0
  1. //
  2. // Simple unique lock guard to detect concurrent access to unsynchronized global data.
  3. //
  4. // This can be a useful tool to debug data races and identify places where a mutex should
  5. // be introduced. Once the race is fixed, you'll likely want to strip out this code...
  6. //
  7.  
  8. // --------------------------------------------------------
  9.  
  10. #include <atomic>
  11. #include <cassert>
  12. #include <cstdio>
  13. #include <cstdlib>
  14. #include <thread>
  15.  
  16. // --------------------------------------------------------
  17.  
  18. class UniqueLockFlag final
  19. {
  20. public:
  21. UniqueLockFlag()
  22. : m_lockCount{ 0 }
  23. { }
  24.  
  25. void lock() { m_lockCount++; }
  26. void unlock() { m_lockCount--; }
  27.  
  28. bool isLocked() const { return m_lockCount == 1; }
  29.  
  30. private:
  31. std::atomic<int> m_lockCount;
  32. };
  33.  
  34. // Or use std::unique_lock<Mtx>
  35. struct UniqueLockChecker final
  36. {
  37. UniqueLockChecker(UniqueLockFlag & l)
  38. : m_lock{ l }
  39. {
  40. if (m_lock.isLocked())
  41. {
  42. std::fprintf(stderr, "Data race detected between threads! Terminating the program now...\n");
  43. std::abort();
  44. }
  45. m_lock.lock();
  46. }
  47.  
  48. ~UniqueLockChecker()
  49. {
  50. m_lock.unlock();
  51. }
  52.  
  53. UniqueLockFlag & m_lock;
  54. };
  55.  
  56. // --------------------------------------------------------
  57.  
  58. static int g_guardedVariable{ 0 };
  59. static UniqueLockFlag g_guardedVariableLock{};
  60.  
  61. void incrementGlobalVar()
  62. {
  63. UniqueLockChecker l{ g_guardedVariableLock };
  64. g_guardedVariable++;
  65.  
  66. // Do some IO, so it is more likely there will be a context switch while we hold the lock.
  67. std::printf("Global Var = %i\n", g_guardedVariable);
  68. }
  69.  
  70. // --------------------------------------------------------
  71.  
  72. int main()
  73. {
  74. // Safe, incrementing from the same thread.
  75. {
  76. incrementGlobalVar();
  77. incrementGlobalVar();
  78. incrementGlobalVar();
  79. incrementGlobalVar();
  80. assert(g_guardedVariable == 4);
  81. }
  82.  
  83. // Safe, run a thread and wait completion.
  84. {
  85. std::thread t0{ &incrementGlobalVar };
  86. t0.join();
  87.  
  88. std::thread t1{ &incrementGlobalVar };
  89. t1.join();
  90.  
  91. assert(g_guardedVariable == 6);
  92. }
  93.  
  94. // Unsafe, attempt concurrent access from different threads - might abort
  95. {
  96. constexpr int NumRuns = 20;
  97.  
  98. std::thread t{ []() {
  99. for (int i = 0; i < NumRuns; ++i)
  100. {
  101. incrementGlobalVar();
  102. }
  103. } };
  104.  
  105. for (int i = 0; i < NumRuns; ++i)
  106. {
  107. incrementGlobalVar();
  108. }
  109.  
  110. t.join();
  111. assert(g_guardedVariable == (NumRuns * 2) + 6);
  112. }
  113. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement