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: |
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 | |
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 | |
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(threadfunc: 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(xt: delay(secs: 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 | |
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(threadfunc: 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(xt: delay(secs: 1)); |
123 | pool.create_thread(threadfunc: 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(m&: 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 | |
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 | |
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(rel_time: 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 | |
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(rel_time: 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 | |
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 | |
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 | |
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(xt: delay(secs: 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 | |
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(xt: delay(secs: 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 | |
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(rel_time: 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 | |