| Left: | ||
| Right: |
| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #include <gtest/gtest.h> | |
| 2 #include <queue> | |
| 3 | |
| 4 #include "../src/Thread.h" | |
| 5 | |
| 6 namespace | |
| 7 { | |
| 8 #ifndef WIN32 | |
| 9 void Sleep(const int millis) | |
| 10 { | |
| 11 usleep(millis * 1000); | |
| 12 } | |
| 13 #endif | |
| 14 | |
| 15 class Mock : public AdblockPlus::Thread | |
| 16 { | |
| 17 public: | |
| 18 int timesCalled; | |
| 19 | |
| 20 Mock() : timesCalled(0) | |
| 21 { | |
| 22 } | |
| 23 | |
| 24 void Run() | |
| 25 { | |
| 26 timesCalled++; | |
|
Wladimir Palant
2013/04/03 13:14:47
This statement isn't thread-safe, you need a mutex
Felix Dahlke
2013/04/03 16:27:59
I thought that's pretty unlikely here, but fair en
| |
| 27 } | |
| 28 }; | |
| 29 | |
| 30 class LockingMock : public AdblockPlus::Thread | |
| 31 { | |
| 32 public: | |
| 33 bool working; | |
| 34 | |
| 35 LockingMock(AdblockPlus::Thread::Mutex& mutex, const int millisToSleep) | |
| 36 : mutex(mutex), millisToSleep(millisToSleep) | |
| 37 { | |
| 38 } | |
| 39 | |
| 40 void Run() | |
| 41 { | |
| 42 mutex.Lock(); | |
| 43 working = true; | |
| 44 Sleep(millisToSleep); | |
| 45 working = false; | |
| 46 mutex.Unlock(); | |
| 47 } | |
| 48 | |
| 49 private: | |
| 50 AdblockPlus::Thread::Mutex& mutex; | |
| 51 int millisToSleep; | |
| 52 }; | |
| 53 | |
| 54 class Enqueuer : public AdblockPlus::Thread | |
| 55 { | |
| 56 public: | |
| 57 Enqueuer(std::queue<int>& queue, AdblockPlus::Thread::Mutex& mutex, | |
| 58 AdblockPlus::Thread::Condition& notEmpty) | |
| 59 : queue(queue), mutex(mutex), notEmpty(notEmpty) | |
| 60 { | |
| 61 } | |
| 62 | |
| 63 void Run() | |
| 64 { | |
| 65 Sleep(5); | |
| 66 mutex.Lock(); | |
| 67 queue.push(1); | |
| 68 Sleep(10); | |
| 69 notEmpty.Signal(); | |
| 70 mutex.Unlock(); | |
| 71 } | |
| 72 | |
| 73 private: | |
| 74 std::queue<int>& queue; | |
| 75 AdblockPlus::Thread::Mutex& mutex; | |
| 76 AdblockPlus::Thread::Condition& notEmpty; | |
| 77 }; | |
| 78 | |
| 79 class Dequeuer : public AdblockPlus::Thread | |
| 80 { | |
| 81 public: | |
| 82 Dequeuer(std::queue<int>& queue, AdblockPlus::Thread::Mutex& mutex, | |
| 83 AdblockPlus::Thread::Condition& notEmpty) | |
| 84 : queue(queue), mutex(mutex), notEmpty(notEmpty) | |
| 85 { | |
| 86 } | |
| 87 | |
| 88 void Run() | |
| 89 { | |
| 90 mutex.Lock(); | |
| 91 if (!queue.size()) | |
| 92 notEmpty.Wait(mutex); | |
| 93 queue.pop(); | |
| 94 mutex.Unlock(); | |
| 95 } | |
| 96 | |
| 97 private: | |
| 98 std::queue<int>& queue; | |
| 99 AdblockPlus::Thread::Mutex& mutex; | |
| 100 AdblockPlus::Thread::Condition& notEmpty; | |
| 101 }; | |
| 102 } | |
| 103 | |
| 104 TEST(ThreadTest, Run) | |
| 105 { | |
| 106 Mock mock; | |
| 107 ASSERT_EQ(0, mock.timesCalled); | |
| 108 mock.Start(); | |
| 109 ASSERT_EQ(0, mock.timesCalled); | |
|
Wladimir Palant
2013/04/03 13:14:47
This is a race condition - by the time you check t
Felix Dahlke
2013/04/03 16:27:59
Yes indeed, made it a bit more robust. It's still
| |
| 110 mock.Join(); | |
| 111 ASSERT_EQ(1, mock.timesCalled); | |
| 112 } | |
| 113 | |
| 114 TEST(ThreadTest, Mutex) | |
| 115 { | |
| 116 AdblockPlus::Thread::Mutex mutex; | |
| 117 LockingMock mock1(mutex, 10); | |
| 118 LockingMock mock2(mutex, 20); | |
| 119 mock1.Start(); | |
| 120 mock2.Start(); | |
| 121 Sleep(5); | |
| 122 ASSERT_TRUE(mock1.working); | |
| 123 ASSERT_FALSE(mock2.working); | |
|
Wladimir Palant
2013/04/03 13:14:47
Please note that Sleep() (both the Windows and the
Felix Dahlke
2013/04/03 16:27:59
Agreed, much more robust that way.
| |
| 124 Sleep(10); | |
| 125 ASSERT_TRUE(mock2.working); | |
| 126 ASSERT_FALSE(mock1.working); | |
| 127 mock1.Join(); | |
| 128 mock2.Join(); | |
| 129 } | |
| 130 | |
| 131 TEST(ThreadTest, ConditionVariable) | |
| 132 { | |
| 133 std::queue<int> queue; | |
| 134 AdblockPlus::Thread::Mutex mutex; | |
| 135 AdblockPlus::Thread::Condition notEmpty; | |
| 136 Enqueuer enqueuer(queue, mutex, notEmpty); | |
| 137 Dequeuer dequeuer(queue, mutex, notEmpty); | |
| 138 enqueuer.Start(); | |
| 139 dequeuer.Start(); | |
| 140 Sleep(10); | |
| 141 ASSERT_EQ(1, queue.size()); | |
|
Wladimir Palant
2013/04/03 13:14:47
Same flaw here as above.
Felix Dahlke
2013/04/03 16:27:59
Fixed as well.
| |
| 142 Sleep(15); | |
| 143 ASSERT_EQ(0, queue.size()); | |
| 144 enqueuer.Join(); | |
| 145 dequeuer.Join(); | |
| 146 } | |
| OLD | NEW |