Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: test/Thread.cpp

Issue 10026001: Cross-platform thread primitives (Closed)
Left Patch Set: Created March 29, 2013, 5:26 a.m.
Right Patch Set: Improve mutex test Created April 4, 2013, 7:27 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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);
29 mutex.Lock();
26 timesCalled++; 30 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
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(std::vector<std::string>& log, AdblockPlus::Mutex& logMutex)
36 : mutex(mutex), millisToSleep(millisToSleep) 41 : log(log), logMutex(logMutex)
37 { 42 {
38 } 43 }
39 44
40 void Run() 45 void Run()
41 { 46 {
42 mutex.Lock(); 47 logMutex.Lock();
43 working = true; 48 log.push_back("started");
44 Sleep(millisToSleep); 49 Sleep(5);
45 working = false; 50 log.push_back("ended");
46 mutex.Unlock(); 51 logMutex.Unlock();
47 } 52 }
48 53
49 private: 54 private:
50 AdblockPlus::Thread::Mutex& mutex; 55 const std::string name;
51 int millisToSleep; 56 std::vector<std::string>& log;
57 AdblockPlus::Mutex& logMutex;
52 }; 58 };
53 59
54 class Enqueuer : public AdblockPlus::Thread 60 class Enqueuer : public AdblockPlus::Thread
55 { 61 {
56 public: 62 public:
57 Enqueuer(std::queue<int>& queue, AdblockPlus::Thread::Mutex& mutex, 63 Enqueuer(std::queue<int>& queue, AdblockPlus::Mutex& queueMutex,
58 AdblockPlus::Thread::Condition& notEmpty) 64 AdblockPlus::ConditionVariable& notEmpty)
59 : queue(queue), mutex(mutex), notEmpty(notEmpty) 65 : queue(queue), queueMutex(queueMutex), notEmpty(notEmpty)
60 { 66 {
61 } 67 }
62 68
63 void Run() 69 void Run()
64 { 70 {
65 Sleep(5); 71 queueMutex.Lock();
66 mutex.Lock();
67 queue.push(1); 72 queue.push(1);
68 Sleep(10);
69 notEmpty.Signal(); 73 notEmpty.Signal();
70 mutex.Unlock(); 74 queueMutex.Unlock();
71 } 75 }
72 76
73 private: 77 private:
74 std::queue<int>& queue; 78 std::queue<int>& queue;
75 AdblockPlus::Thread::Mutex& mutex; 79 AdblockPlus::Mutex& queueMutex;
76 AdblockPlus::Thread::Condition& notEmpty; 80 AdblockPlus::ConditionVariable& notEmpty;
77 }; 81 };
78 82
79 class Dequeuer : public AdblockPlus::Thread 83 class Dequeuer : public AdblockPlus::Thread
80 { 84 {
81 public: 85 public:
82 Dequeuer(std::queue<int>& queue, AdblockPlus::Thread::Mutex& mutex, 86 Dequeuer(std::queue<int>& queue, AdblockPlus::Mutex& queueMutex,
83 AdblockPlus::Thread::Condition& notEmpty) 87 AdblockPlus::ConditionVariable& notEmpty)
84 : queue(queue), mutex(mutex), notEmpty(notEmpty) 88 : queue(queue), queueMutex(queueMutex), notEmpty(notEmpty)
85 { 89 {
86 } 90 }
87 91
88 void Run() 92 void Run()
89 { 93 {
90 mutex.Lock(); 94 queueMutex.Lock();
91 if (!queue.size()) 95 if (!queue.size())
92 notEmpty.Wait(mutex); 96 notEmpty.Wait(queueMutex);
93 queue.pop(); 97 queue.pop();
94 mutex.Unlock(); 98 queueMutex.Unlock();
95 } 99 }
96 100
97 private: 101 private:
98 std::queue<int>& queue; 102 std::queue<int>& queue;
99 AdblockPlus::Thread::Mutex& mutex; 103 AdblockPlus::Mutex& queueMutex;
100 AdblockPlus::Thread::Condition& notEmpty; 104 AdblockPlus::ConditionVariable& notEmpty;
101 }; 105 };
102 } 106 }
103 107
104 TEST(ThreadTest, Run) 108 TEST(ThreadTest, Run)
105 { 109 {
106 Mock mock; 110 Mock mock;
107 ASSERT_EQ(0, mock.timesCalled); 111 ASSERT_EQ(0, mock.timesCalled);
108 mock.Start(); 112 mock.Start();
113 mock.mutex.Lock();
109 ASSERT_EQ(0, mock.timesCalled); 114 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
115 mock.mutex.Unlock();
110 mock.Join(); 116 mock.Join();
111 ASSERT_EQ(1, mock.timesCalled); 117 ASSERT_EQ(1, mock.timesCalled);
112 } 118 }
113 119
114 TEST(ThreadTest, Mutex) 120 TEST(ThreadTest, Mutex)
115 { 121 {
116 AdblockPlus::Thread::Mutex mutex; 122 std::vector<std::string> log;
117 LockingMock mock1(mutex, 10); 123 AdblockPlus::Mutex logMutex;
118 LockingMock mock2(mutex, 20); 124 LockingMock mock1(log, logMutex);
125 LockingMock mock2(log, logMutex);
119 mock1.Start(); 126 mock1.Start();
120 mock2.Start(); 127 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 mock1.Join();
128 mock2.Join(); 129 mock2.Join();
130 ASSERT_EQ("started", log[0]);
131 ASSERT_EQ("ended", log[1]);
132 ASSERT_EQ("started", log[2]);
133 ASSERT_EQ("ended", log[3]);
129 } 134 }
130 135
131 TEST(ThreadTest, ConditionVariable) 136 TEST(ThreadTest, ConditionVariable)
132 { 137 {
133 std::queue<int> queue; 138 std::queue<int> queue;
134 AdblockPlus::Thread::Mutex mutex; 139 AdblockPlus::Mutex queueMutex;
135 AdblockPlus::Thread::Condition notEmpty; 140 AdblockPlus::ConditionVariable notEmpty;
136 Enqueuer enqueuer(queue, mutex, notEmpty); 141 Dequeuer dequeuer(queue, queueMutex, notEmpty);
137 Dequeuer dequeuer(queue, mutex, notEmpty); 142 Enqueuer enqueuer(queue, queueMutex, notEmpty);
143 dequeuer.Start();
144 Sleep(5);
138 enqueuer.Start(); 145 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(); 146 enqueuer.Join();
145 dequeuer.Join(); 147 dequeuer.Join();
148 ASSERT_EQ(0, queue.size());
146 } 149 }
LEFTRIGHT
« no previous file | no next file » | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

Powered by Google App Engine
This is Rietveld