lock_unittest.cc 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "butil/synchronization/lock.h"
  5. #include <stdlib.h>
  6. #include "butil/compiler_specific.h"
  7. #include "butil/threading/platform_thread.h"
  8. #include <gtest/gtest.h>
  9. namespace butil {
  10. // Basic test to make sure that Acquire()/Release()/Try() don't crash ----------
  11. class BasicLockTestThread : public PlatformThread::Delegate {
  12. public:
  13. explicit BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {}
  14. virtual void ThreadMain() OVERRIDE {
  15. for (int i = 0; i < 10; i++) {
  16. lock_->Acquire();
  17. acquired_++;
  18. lock_->Release();
  19. }
  20. for (int i = 0; i < 10; i++) {
  21. lock_->Acquire();
  22. acquired_++;
  23. PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
  24. lock_->Release();
  25. }
  26. for (int i = 0; i < 10; i++) {
  27. if (lock_->Try()) {
  28. acquired_++;
  29. PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
  30. lock_->Release();
  31. }
  32. }
  33. }
  34. int acquired() const { return acquired_; }
  35. private:
  36. Lock* lock_;
  37. int acquired_;
  38. DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread);
  39. };
  40. TEST(LockTest, Basic) {
  41. Lock lock;
  42. BasicLockTestThread thread(&lock);
  43. PlatformThreadHandle handle;
  44. ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
  45. int acquired = 0;
  46. for (int i = 0; i < 5; i++) {
  47. lock.Acquire();
  48. acquired++;
  49. lock.Release();
  50. }
  51. for (int i = 0; i < 10; i++) {
  52. lock.Acquire();
  53. acquired++;
  54. PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
  55. lock.Release();
  56. }
  57. for (int i = 0; i < 10; i++) {
  58. if (lock.Try()) {
  59. acquired++;
  60. PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
  61. lock.Release();
  62. }
  63. }
  64. for (int i = 0; i < 5; i++) {
  65. lock.Acquire();
  66. acquired++;
  67. PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
  68. lock.Release();
  69. }
  70. PlatformThread::Join(handle);
  71. EXPECT_GE(acquired, 20);
  72. EXPECT_GE(thread.acquired(), 20);
  73. }
  74. // Test that Try() works as expected -------------------------------------------
  75. class TryLockTestThread : public PlatformThread::Delegate {
  76. public:
  77. explicit TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {}
  78. virtual void ThreadMain() OVERRIDE {
  79. got_lock_ = lock_->Try();
  80. if (got_lock_)
  81. lock_->Release();
  82. }
  83. bool got_lock() const { return got_lock_; }
  84. private:
  85. Lock* lock_;
  86. bool got_lock_;
  87. DISALLOW_COPY_AND_ASSIGN(TryLockTestThread);
  88. };
  89. TEST(LockTest, TryLock) {
  90. Lock lock;
  91. ASSERT_TRUE(lock.Try());
  92. // We now have the lock....
  93. // This thread will not be able to get the lock.
  94. {
  95. TryLockTestThread thread(&lock);
  96. PlatformThreadHandle handle;
  97. ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
  98. PlatformThread::Join(handle);
  99. ASSERT_FALSE(thread.got_lock());
  100. }
  101. lock.Release();
  102. // This thread will....
  103. {
  104. TryLockTestThread thread(&lock);
  105. PlatformThreadHandle handle;
  106. ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
  107. PlatformThread::Join(handle);
  108. ASSERT_TRUE(thread.got_lock());
  109. // But it released it....
  110. ASSERT_TRUE(lock.Try());
  111. }
  112. lock.Release();
  113. }
  114. // Tests that locks actually exclude -------------------------------------------
  115. class MutexLockTestThread : public PlatformThread::Delegate {
  116. public:
  117. MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {}
  118. // Static helper which can also be called from the main thread.
  119. static void DoStuff(Lock* lock, int* value) {
  120. for (int i = 0; i < 40; i++) {
  121. lock->Acquire();
  122. int v = *value;
  123. PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10));
  124. *value = v + 1;
  125. lock->Release();
  126. }
  127. }
  128. virtual void ThreadMain() OVERRIDE {
  129. DoStuff(lock_, value_);
  130. }
  131. private:
  132. Lock* lock_;
  133. int* value_;
  134. DISALLOW_COPY_AND_ASSIGN(MutexLockTestThread);
  135. };
  136. TEST(LockTest, MutexTwoThreads) {
  137. Lock lock;
  138. int value = 0;
  139. MutexLockTestThread thread(&lock, &value);
  140. PlatformThreadHandle handle;
  141. ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
  142. MutexLockTestThread::DoStuff(&lock, &value);
  143. PlatformThread::Join(handle);
  144. EXPECT_EQ(2 * 40, value);
  145. }
  146. TEST(LockTest, MutexFourThreads) {
  147. Lock lock;
  148. int value = 0;
  149. MutexLockTestThread thread1(&lock, &value);
  150. MutexLockTestThread thread2(&lock, &value);
  151. MutexLockTestThread thread3(&lock, &value);
  152. PlatformThreadHandle handle1;
  153. PlatformThreadHandle handle2;
  154. PlatformThreadHandle handle3;
  155. ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1));
  156. ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2));
  157. ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3));
  158. MutexLockTestThread::DoStuff(&lock, &value);
  159. PlatformThread::Join(handle1);
  160. PlatformThread::Join(handle2);
  161. PlatformThread::Join(handle3);
  162. EXPECT_EQ(4 * 40, value);
  163. }
  164. } // namespace butil