1 // (C) Copyright 2006-7 Anthony Williams
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5
6 #define BOOST_THREAD_VERSION 2
7 #define BOOST_TEST_MODULE Boost.Threads: shared_mutex_part2 test suite
8
9 #include <boost/config.hpp>
10 #include <boost/test/unit_test.hpp>
11 #include <boost/thread/thread.hpp>
12 #include <boost/thread/xtime.hpp>
13 #include "./util.inl"
14 #include "./shared_mutex_locking_thread.hpp"
15
16 #define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
17 { \
18 boost::unique_lock<boost::mutex> lock(mutex_name); \
19 BOOST_CHECK_EQUAL(value,expected_value); \
20 }
21
22 class simple_upgrade_thread
23 {
24 boost::shared_mutex& rwm;
25 boost::mutex& finish_mutex;
26 boost::mutex& unblocked_mutex;
27 unsigned& unblocked_count;
28
29 void operator=(simple_upgrade_thread&);
30
31 public:
simple_upgrade_thread(boost::shared_mutex & rwm_,boost::mutex & finish_mutex_,boost::mutex & unblocked_mutex_,unsigned & unblocked_count_)32 simple_upgrade_thread(boost::shared_mutex& rwm_,
33 boost::mutex& finish_mutex_,
34 boost::mutex& unblocked_mutex_,
35 unsigned& unblocked_count_):
36 rwm(rwm_),finish_mutex(finish_mutex_),
37 unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
38 {}
39
40 #if !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS)
41 simple_upgrade_thread(simple_upgrade_thread const&) = default;
42 #endif
43
operator ()()44 void operator()()
45 {
46 boost::upgrade_lock<boost::shared_mutex> lk(rwm);
47
48 {
49 boost::unique_lock<boost::mutex> ulk(unblocked_mutex);
50 ++unblocked_count;
51 }
52
53 boost::unique_lock<boost::mutex> flk(finish_mutex);
54 }
55 };
56
57
BOOST_AUTO_TEST_CASE(test_only_one_upgrade_lock_permitted)58 BOOST_AUTO_TEST_CASE(test_only_one_upgrade_lock_permitted)
59 {
60 unsigned const number_of_threads=2;
61
62 boost::thread_group pool;
63
64 boost::shared_mutex rw_mutex;
65 unsigned unblocked_count=0;
66 unsigned simultaneous_running_count=0;
67 unsigned max_simultaneous_running=0;
68 boost::mutex unblocked_count_mutex;
69 boost::condition_variable unblocked_condition;
70 boost::mutex finish_mutex;
71 boost::unique_lock<boost::mutex> finish_lock(finish_mutex);
72
73 try
74 {
75 for(unsigned i=0;i<number_of_threads;++i)
76 {
77 pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
78 finish_mutex,simultaneous_running_count,max_simultaneous_running));
79 }
80
81 boost::thread::sleep(delay(1));
82
83 CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
84
85 finish_lock.unlock();
86
87 pool.join_all();
88 }
89 catch(...)
90 {
91 pool.interrupt_all();
92 pool.join_all();
93 throw;
94 }
95
96 CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
97 CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
98 }
99
BOOST_AUTO_TEST_CASE(test_can_lock_upgrade_if_currently_locked_shared)100 BOOST_AUTO_TEST_CASE(test_can_lock_upgrade_if_currently_locked_shared)
101 {
102 boost::thread_group pool;
103
104 boost::shared_mutex rw_mutex;
105 unsigned unblocked_count=0;
106 unsigned simultaneous_running_count=0;
107 unsigned max_simultaneous_running=0;
108 boost::mutex unblocked_count_mutex;
109 boost::condition_variable unblocked_condition;
110 boost::mutex finish_mutex;
111 boost::unique_lock<boost::mutex> finish_lock(finish_mutex);
112
113 unsigned const reader_count=10;
114
115 try
116 {
117 for(unsigned i=0;i<reader_count;++i)
118 {
119 pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
120 finish_mutex,simultaneous_running_count,max_simultaneous_running));
121 }
122 boost::thread::sleep(delay(1));
123 pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
124 finish_mutex,simultaneous_running_count,max_simultaneous_running));
125 {
126 boost::unique_lock<boost::mutex> lk(unblocked_count_mutex);
127 while(unblocked_count<(reader_count+1))
128 {
129 unblocked_condition.wait(lk);
130 }
131 }
132 CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
133
134 finish_lock.unlock();
135 pool.join_all();
136 }
137 catch(...)
138 {
139 pool.interrupt_all();
140 pool.join_all();
141 throw;
142 }
143
144
145 CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
146 CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count+1);
147 }
148
BOOST_AUTO_TEST_CASE(test_can_lock_upgrade_to_unique_if_currently_locked_upgrade)149 BOOST_AUTO_TEST_CASE(test_can_lock_upgrade_to_unique_if_currently_locked_upgrade)
150 {
151 boost::shared_mutex mtx;
152 boost::upgrade_lock<boost::shared_mutex> l(mtx);
153 boost::upgrade_to_unique_lock<boost::shared_mutex> ul(l);
154 BOOST_CHECK(ul.owns_lock());
155 }
156
BOOST_AUTO_TEST_CASE(test_if_other_thread_has_write_lock_try_lock_shared_returns_false)157 BOOST_AUTO_TEST_CASE(test_if_other_thread_has_write_lock_try_lock_shared_returns_false)
158 {
159
160 boost::shared_mutex rw_mutex;
161 boost::mutex finish_mutex;
162 boost::mutex unblocked_mutex;
163 unsigned unblocked_count=0;
164 boost::unique_lock<boost::mutex> finish_lock(finish_mutex);
165 boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
166 boost::this_thread::sleep(boost::posix_time::seconds(1));
167 CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
168
169 bool const try_succeeded=rw_mutex.try_lock_shared();
170 BOOST_CHECK(!try_succeeded);
171 if(try_succeeded)
172 {
173 rw_mutex.unlock_shared();
174 }
175
176 finish_lock.unlock();
177 writer.join();
178 }
179
BOOST_AUTO_TEST_CASE(test_if_other_thread_has_write_lock_try_lock_upgrade_returns_false)180 BOOST_AUTO_TEST_CASE(test_if_other_thread_has_write_lock_try_lock_upgrade_returns_false)
181 {
182
183 boost::shared_mutex rw_mutex;
184 boost::mutex finish_mutex;
185 boost::mutex unblocked_mutex;
186 unsigned unblocked_count=0;
187 boost::unique_lock<boost::mutex> finish_lock(finish_mutex);
188 boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
189 boost::this_thread::sleep(boost::posix_time::seconds(1));
190 CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
191
192 bool const try_succeeded=rw_mutex.try_lock_upgrade();
193 BOOST_CHECK(!try_succeeded);
194 if(try_succeeded)
195 {
196 rw_mutex.unlock_upgrade();
197 }
198
199 finish_lock.unlock();
200 writer.join();
201 }
202
BOOST_AUTO_TEST_CASE(test_if_no_thread_has_lock_try_lock_shared_returns_true)203 BOOST_AUTO_TEST_CASE(test_if_no_thread_has_lock_try_lock_shared_returns_true)
204 {
205 boost::shared_mutex rw_mutex;
206 bool const try_succeeded=rw_mutex.try_lock_shared();
207 BOOST_CHECK(try_succeeded);
208 if(try_succeeded)
209 {
210 rw_mutex.unlock_shared();
211 }
212 }
213
BOOST_AUTO_TEST_CASE(test_if_no_thread_has_lock_try_lock_upgrade_returns_true)214 BOOST_AUTO_TEST_CASE(test_if_no_thread_has_lock_try_lock_upgrade_returns_true)
215 {
216 boost::shared_mutex rw_mutex;
217 bool const try_succeeded=rw_mutex.try_lock_upgrade();
218 BOOST_CHECK(try_succeeded);
219 if(try_succeeded)
220 {
221 rw_mutex.unlock_upgrade();
222 }
223 }
224
BOOST_AUTO_TEST_CASE(test_if_other_thread_has_shared_lock_try_lock_shared_returns_true)225 BOOST_AUTO_TEST_CASE(test_if_other_thread_has_shared_lock_try_lock_shared_returns_true)
226 {
227
228 boost::shared_mutex rw_mutex;
229 boost::mutex finish_mutex;
230 boost::mutex unblocked_mutex;
231 unsigned unblocked_count=0;
232 boost::unique_lock<boost::mutex> finish_lock(finish_mutex);
233 boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
234 boost::thread::sleep(delay(1));
235 CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
236
237 bool const try_succeeded=rw_mutex.try_lock_shared();
238 BOOST_CHECK(try_succeeded);
239 if(try_succeeded)
240 {
241 rw_mutex.unlock_shared();
242 }
243
244 finish_lock.unlock();
245 writer.join();
246 }
247
BOOST_AUTO_TEST_CASE(test_if_other_thread_has_shared_lock_try_lock_upgrade_returns_true)248 BOOST_AUTO_TEST_CASE(test_if_other_thread_has_shared_lock_try_lock_upgrade_returns_true)
249 {
250
251 boost::shared_mutex rw_mutex;
252 boost::mutex finish_mutex;
253 boost::mutex unblocked_mutex;
254 unsigned unblocked_count=0;
255 boost::unique_lock<boost::mutex> finish_lock(finish_mutex);
256 boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
257 boost::thread::sleep(delay(1));
258 CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
259
260 bool const try_succeeded=rw_mutex.try_lock_upgrade();
261 BOOST_CHECK(try_succeeded);
262 if(try_succeeded)
263 {
264 rw_mutex.unlock_upgrade();
265 }
266
267 finish_lock.unlock();
268 writer.join();
269 }
270
BOOST_AUTO_TEST_CASE(test_if_other_thread_has_upgrade_lock_try_lock_upgrade_returns_false)271 BOOST_AUTO_TEST_CASE(test_if_other_thread_has_upgrade_lock_try_lock_upgrade_returns_false)
272 {
273
274 boost::shared_mutex rw_mutex;
275 boost::mutex finish_mutex;
276 boost::mutex unblocked_mutex;
277 unsigned unblocked_count=0;
278 boost::unique_lock<boost::mutex> finish_lock(finish_mutex);
279 boost::thread writer(simple_upgrade_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
280 boost::this_thread::sleep(boost::posix_time::seconds(1));
281 CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
282
283 bool const try_succeeded=rw_mutex.try_lock_upgrade();
284 BOOST_CHECK(!try_succeeded);
285 if(try_succeeded)
286 {
287 rw_mutex.unlock_upgrade();
288 }
289
290 finish_lock.unlock();
291 writer.join();
292 }
293
294
295