| Left: | ||
| Right: |
| OLD | NEW |
|---|---|
| 1 #include <gtest/gtest.h> | 1 #include <gtest/gtest.h> |
| 2 #include <queue> | 2 #include <queue> |
| 3 #include <vector> | |
| 3 | 4 |
| 4 #include "../src/Thread.h" | 5 #include "../src/Thread.h" |
| 5 | 6 |
| 6 namespace | 7 namespace |
| 7 { | 8 { |
| 8 #ifndef WIN32 | 9 #ifndef WIN32 |
| 9 void Sleep(const int millis) | 10 void Sleep(const int millis) |
| 10 { | 11 { |
| 11 usleep(millis * 1000); | 12 usleep(millis * 1000); |
| 12 } | 13 } |
| 13 #endif | 14 #endif |
| 14 | 15 |
| 15 class Mock : public AdblockPlus::Thread | 16 class Mock : public AdblockPlus::Thread |
| 16 { | 17 { |
| 17 public: | 18 public: |
| 18 int timesCalled; | 19 int timesCalled; |
| 20 AdblockPlus::Mutex mutex; | |
| 19 | 21 |
| 20 Mock() : timesCalled(0) | 22 Mock() : timesCalled(0) |
| 21 { | 23 { |
| 22 } | 24 } |
| 23 | 25 |
| 24 void Run() | 26 void Run() |
| 25 { | 27 { |
| 28 Sleep(5); | |
|
Wladimir Palant
2013/04/04 07:09:00
Why is this necessary? Seems random.
Felix Dahlke
2013/04/04 07:27:40
See below.
| |
| 29 mutex.Lock(); | |
| 26 timesCalled++; | 30 timesCalled++; |
| 31 mutex.Unlock(); | |
| 27 } | 32 } |
| 28 }; | 33 }; |
| 29 | 34 |
| 30 class LockingMock : public AdblockPlus::Thread | 35 class LockingMock : public AdblockPlus::Thread |
| 31 { | 36 { |
| 32 public: | 37 public: |
| 33 bool working; | 38 bool working; |
| 34 | 39 |
| 35 LockingMock(AdblockPlus::Thread::Mutex& mutex, const int millisToSleep) | 40 LockingMock(const std::string& name, std::vector<std::string>& log, |
| 36 : mutex(mutex), millisToSleep(millisToSleep) | 41 AdblockPlus::Mutex& logMutex) |
| 42 : name(name), log(log), logMutex(logMutex) | |
| 37 { | 43 { |
| 38 } | 44 } |
| 39 | 45 |
| 40 void Run() | 46 void Run() |
| 41 { | 47 { |
| 42 mutex.Lock(); | 48 logMutex.Lock(); |
| 43 working = true; | 49 log.push_back(name); |
| 44 Sleep(millisToSleep); | 50 logMutex.Unlock(); |
| 45 working = false; | |
| 46 mutex.Unlock(); | |
| 47 } | 51 } |
| 48 | 52 |
| 49 private: | 53 private: |
| 50 AdblockPlus::Thread::Mutex& mutex; | 54 const std::string name; |
| 51 int millisToSleep; | 55 std::vector<std::string>& log; |
| 56 AdblockPlus::Mutex& logMutex; | |
| 52 }; | 57 }; |
| 53 | 58 |
| 54 class Enqueuer : public AdblockPlus::Thread | 59 class Enqueuer : public AdblockPlus::Thread |
| 55 { | 60 { |
| 56 public: | 61 public: |
| 57 Enqueuer(std::queue<int>& queue, AdblockPlus::Thread::Mutex& mutex, | 62 Enqueuer(std::queue<int>& queue, AdblockPlus::Mutex& queueMutex, |
| 58 AdblockPlus::Thread::Condition& notEmpty) | 63 AdblockPlus::ConditionVariable& notEmpty) |
| 59 : queue(queue), mutex(mutex), notEmpty(notEmpty) | 64 : queue(queue), queueMutex(queueMutex), notEmpty(notEmpty) |
| 60 { | 65 { |
| 61 } | 66 } |
| 62 | 67 |
| 63 void Run() | 68 void Run() |
| 64 { | 69 { |
| 65 Sleep(5); | 70 queueMutex.Lock(); |
| 66 mutex.Lock(); | |
| 67 queue.push(1); | 71 queue.push(1); |
| 68 Sleep(10); | |
| 69 notEmpty.Signal(); | 72 notEmpty.Signal(); |
| 70 mutex.Unlock(); | 73 queueMutex.Unlock(); |
| 71 } | 74 } |
| 72 | 75 |
| 73 private: | 76 private: |
| 74 std::queue<int>& queue; | 77 std::queue<int>& queue; |
| 75 AdblockPlus::Thread::Mutex& mutex; | 78 AdblockPlus::Mutex& queueMutex; |
| 76 AdblockPlus::Thread::Condition& notEmpty; | 79 AdblockPlus::ConditionVariable& notEmpty; |
| 77 }; | 80 }; |
| 78 | 81 |
| 79 class Dequeuer : public AdblockPlus::Thread | 82 class Dequeuer : public AdblockPlus::Thread |
| 80 { | 83 { |
| 81 public: | 84 public: |
| 82 Dequeuer(std::queue<int>& queue, AdblockPlus::Thread::Mutex& mutex, | 85 Dequeuer(std::queue<int>& queue, AdblockPlus::Mutex& queueMutex, |
| 83 AdblockPlus::Thread::Condition& notEmpty) | 86 AdblockPlus::ConditionVariable& notEmpty) |
| 84 : queue(queue), mutex(mutex), notEmpty(notEmpty) | 87 : queue(queue), queueMutex(queueMutex), notEmpty(notEmpty) |
| 85 { | 88 { |
| 86 } | 89 } |
| 87 | 90 |
| 88 void Run() | 91 void Run() |
| 89 { | 92 { |
| 90 mutex.Lock(); | 93 queueMutex.Lock(); |
| 91 if (!queue.size()) | 94 if (!queue.size()) |
| 92 notEmpty.Wait(mutex); | 95 notEmpty.Wait(queueMutex); |
| 93 queue.pop(); | 96 queue.pop(); |
| 94 mutex.Unlock(); | 97 queueMutex.Unlock(); |
| 95 } | 98 } |
| 96 | 99 |
| 97 private: | 100 private: |
| 98 std::queue<int>& queue; | 101 std::queue<int>& queue; |
| 99 AdblockPlus::Thread::Mutex& mutex; | 102 AdblockPlus::Mutex& queueMutex; |
| 100 AdblockPlus::Thread::Condition& notEmpty; | 103 AdblockPlus::ConditionVariable& notEmpty; |
| 101 }; | 104 }; |
| 102 } | 105 } |
| 103 | 106 |
| 104 TEST(ThreadTest, Run) | 107 TEST(ThreadTest, Run) |
| 105 { | 108 { |
| 106 Mock mock; | 109 Mock mock; |
| 107 ASSERT_EQ(0, mock.timesCalled); | 110 ASSERT_EQ(0, mock.timesCalled); |
| 108 mock.Start(); | 111 mock.Start(); |
| 112 mock.mutex.Lock(); | |
|
Wladimir Palant
2013/04/04 07:09:00
This should be done before mock.Start(), otherwise
Felix Dahlke
2013/04/04 07:27:40
That's what the 5ms sleep above is for. It's not b
Wladimir Palant
2013/04/04 09:26:53
Oh well :-(
| |
| 109 ASSERT_EQ(0, mock.timesCalled); | 113 ASSERT_EQ(0, mock.timesCalled); |
| 114 mock.mutex.Unlock(); | |
| 110 mock.Join(); | 115 mock.Join(); |
| 111 ASSERT_EQ(1, mock.timesCalled); | 116 ASSERT_EQ(1, mock.timesCalled); |
| 112 } | 117 } |
| 113 | 118 |
| 114 TEST(ThreadTest, Mutex) | 119 TEST(ThreadTest, Mutex) |
| 115 { | 120 { |
| 116 AdblockPlus::Thread::Mutex mutex; | 121 std::vector<std::string> log; |
| 117 LockingMock mock1(mutex, 10); | 122 AdblockPlus::Mutex logMutex; |
| 118 LockingMock mock2(mutex, 20); | 123 LockingMock mock1("mock1", log, logMutex); |
| 124 LockingMock mock2("mock2", log, logMutex); | |
| 119 mock1.Start(); | 125 mock1.Start(); |
| 126 Sleep(5); | |
| 120 mock2.Start(); | 127 mock2.Start(); |
|
Wladimir Palant
2013/04/04 07:09:00
This test doesn't make sense - mock1 will already
Felix Dahlke
2013/04/04 07:27:40
Yeah, that's a much better test. Did that.
| |
| 121 Sleep(5); | |
| 122 ASSERT_TRUE(mock1.working); | |
| 123 ASSERT_FALSE(mock2.working); | |
| 124 Sleep(10); | |
| 125 ASSERT_TRUE(mock2.working); | |
| 126 ASSERT_FALSE(mock1.working); | |
| 127 mock1.Join(); | 128 mock1.Join(); |
| 128 mock2.Join(); | 129 mock2.Join(); |
| 130 ASSERT_EQ("mock1", log[0]); | |
| 131 ASSERT_EQ("mock2", log[1]); | |
| 129 } | 132 } |
| 130 | 133 |
| 131 TEST(ThreadTest, ConditionVariable) | 134 TEST(ThreadTest, ConditionVariable) |
| 132 { | 135 { |
| 133 std::queue<int> queue; | 136 std::queue<int> queue; |
| 134 AdblockPlus::Thread::Mutex mutex; | 137 AdblockPlus::Mutex queueMutex; |
| 135 AdblockPlus::Thread::Condition notEmpty; | 138 AdblockPlus::ConditionVariable notEmpty; |
| 136 Enqueuer enqueuer(queue, mutex, notEmpty); | 139 Dequeuer dequeuer(queue, queueMutex, notEmpty); |
| 137 Dequeuer dequeuer(queue, mutex, notEmpty); | 140 Enqueuer enqueuer(queue, queueMutex, notEmpty); |
| 141 dequeuer.Start(); | |
| 142 Sleep(5); | |
| 138 enqueuer.Start(); | 143 enqueuer.Start(); |
| 139 dequeuer.Start(); | |
| 140 Sleep(10); | |
| 141 ASSERT_EQ(1u, queue.size()); | |
| 142 Sleep(15); | |
| 143 ASSERT_EQ(0u, queue.size()); | |
| 144 enqueuer.Join(); | 144 enqueuer.Join(); |
| 145 dequeuer.Join(); | 145 dequeuer.Join(); |
| 146 ASSERT_EQ(0, queue.size()); | |
|
Wladimir Palant
2013/04/04 09:26:53
This fails to compile for me once again, 0u please
| |
| 146 } | 147 } |
| OLD | NEW |