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_THREAD_PROVIDES_INTERRUPTIONS |
8 | #define BOOST_TEST_MODULE Boost.Threads: shared_mutex test suite |
9 | |
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 | #include <iostream> |
16 | |
17 | #define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \ |
18 | { \ |
19 | boost::unique_lock<boost::mutex> lock(mutex_name); \ |
20 | BOOST_CHECK_EQUAL(value,expected_value); \ |
21 | } |
22 | |
23 | BOOST_AUTO_TEST_CASE(test_multiple_readers) |
24 | { |
25 | std::cout << __LINE__ << std::endl; |
26 | unsigned const number_of_threads=10; |
27 | |
28 | boost::thread_group pool; |
29 | |
30 | boost::shared_mutex rw_mutex; |
31 | unsigned unblocked_count=0; |
32 | unsigned simultaneous_running_count=0; |
33 | unsigned max_simultaneous_running=0; |
34 | boost::mutex unblocked_count_mutex; |
35 | boost::condition_variable unblocked_condition; |
36 | boost::mutex finish_mutex; |
37 | boost::unique_lock<boost::mutex> finish_lock(finish_mutex); |
38 | |
39 | try |
40 | { |
41 | for(unsigned i=0;i<number_of_threads;++i) |
42 | { |
43 | pool.create_thread(threadfunc: locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, |
44 | finish_mutex,simultaneous_running_count,max_simultaneous_running)); |
45 | } |
46 | |
47 | { |
48 | boost::unique_lock<boost::mutex> lk(unblocked_count_mutex); |
49 | while(unblocked_count<number_of_threads) |
50 | { |
51 | unblocked_condition.wait(m&: lk); |
52 | } |
53 | } |
54 | |
55 | CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads); |
56 | |
57 | finish_lock.unlock(); |
58 | |
59 | pool.join_all(); |
60 | } |
61 | catch(...) |
62 | { |
63 | pool.interrupt_all(); |
64 | pool.join_all(); |
65 | throw; |
66 | } |
67 | |
68 | CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,number_of_threads); |
69 | } |
70 | |
71 | BOOST_AUTO_TEST_CASE(test_only_one_writer_permitted) |
72 | { |
73 | std::cout << __LINE__ << std::endl; |
74 | unsigned const number_of_threads=10; |
75 | |
76 | boost::thread_group pool; |
77 | |
78 | boost::shared_mutex rw_mutex; |
79 | unsigned unblocked_count=0; |
80 | unsigned simultaneous_running_count=0; |
81 | unsigned max_simultaneous_running=0; |
82 | boost::mutex unblocked_count_mutex; |
83 | boost::condition_variable unblocked_condition; |
84 | boost::mutex finish_mutex; |
85 | boost::unique_lock<boost::mutex> finish_lock(finish_mutex); |
86 | |
87 | try |
88 | { |
89 | for(unsigned i=0;i<number_of_threads;++i) |
90 | { |
91 | pool.create_thread(threadfunc: locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, |
92 | finish_mutex,simultaneous_running_count,max_simultaneous_running)); |
93 | } |
94 | |
95 | boost::thread::sleep(xt: delay(secs: 2)); |
96 | |
97 | CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); |
98 | |
99 | finish_lock.unlock(); |
100 | |
101 | pool.join_all(); |
102 | } |
103 | catch(...) |
104 | { |
105 | pool.interrupt_all(); |
106 | pool.join_all(); |
107 | throw; |
108 | } |
109 | |
110 | CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads); |
111 | CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u); |
112 | } |
113 | |
114 | BOOST_AUTO_TEST_CASE(test_reader_blocks_writer) |
115 | { |
116 | std::cout << __LINE__ << std::endl; |
117 | boost::thread_group pool; |
118 | |
119 | boost::shared_mutex rw_mutex; |
120 | unsigned unblocked_count=0; |
121 | unsigned simultaneous_running_count=0; |
122 | unsigned max_simultaneous_running=0; |
123 | boost::mutex unblocked_count_mutex; |
124 | boost::condition_variable unblocked_condition; |
125 | boost::mutex finish_mutex; |
126 | boost::unique_lock<boost::mutex> finish_lock(finish_mutex); |
127 | |
128 | try |
129 | { |
130 | |
131 | pool.create_thread(threadfunc: locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, |
132 | finish_mutex,simultaneous_running_count,max_simultaneous_running)); |
133 | { |
134 | boost::unique_lock<boost::mutex> lk(unblocked_count_mutex); |
135 | while(unblocked_count<1) |
136 | { |
137 | unblocked_condition.wait(m&: lk); |
138 | } |
139 | } |
140 | CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); |
141 | pool.create_thread(threadfunc: locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, |
142 | finish_mutex,simultaneous_running_count,max_simultaneous_running)); |
143 | boost::thread::sleep(xt: delay(secs: 1)); |
144 | CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); |
145 | |
146 | finish_lock.unlock(); |
147 | |
148 | pool.join_all(); |
149 | } |
150 | catch(...) |
151 | { |
152 | pool.interrupt_all(); |
153 | pool.join_all(); |
154 | throw; |
155 | } |
156 | |
157 | CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,2U); |
158 | CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u); |
159 | } |
160 | |
161 | BOOST_AUTO_TEST_CASE(test_unlocking_writer_unblocks_all_readers) |
162 | { |
163 | std::cout << __LINE__ << std::endl; |
164 | boost::thread_group pool; |
165 | |
166 | boost::shared_mutex rw_mutex; |
167 | boost::unique_lock<boost::shared_mutex> write_lock(rw_mutex); |
168 | unsigned unblocked_count=0; |
169 | unsigned simultaneous_running_count=0; |
170 | unsigned max_simultaneous_running=0; |
171 | boost::mutex unblocked_count_mutex; |
172 | boost::condition_variable unblocked_condition; |
173 | boost::mutex finish_mutex; |
174 | boost::unique_lock<boost::mutex> finish_lock(finish_mutex); |
175 | |
176 | unsigned const reader_count=10; |
177 | |
178 | try |
179 | { |
180 | for(unsigned i=0;i<reader_count;++i) |
181 | { |
182 | pool.create_thread(threadfunc: locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, |
183 | finish_mutex,simultaneous_running_count,max_simultaneous_running)); |
184 | } |
185 | boost::thread::sleep(xt: delay(secs: 1)); |
186 | CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,0U); |
187 | |
188 | write_lock.unlock(); |
189 | |
190 | { |
191 | boost::unique_lock<boost::mutex> lk(unblocked_count_mutex); |
192 | while(unblocked_count<reader_count) |
193 | { |
194 | unblocked_condition.wait(m&: lk); |
195 | } |
196 | } |
197 | |
198 | CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count); |
199 | |
200 | finish_lock.unlock(); |
201 | pool.join_all(); |
202 | } |
203 | catch(...) |
204 | { |
205 | pool.interrupt_all(); |
206 | pool.join_all(); |
207 | throw; |
208 | } |
209 | |
210 | CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count); |
211 | } |
212 | |
213 | BOOST_AUTO_TEST_CASE(test_unlocking_last_reader_only_unblocks_one_writer) |
214 | { |
215 | std::cout << __LINE__ << std::endl; |
216 | boost::thread_group pool; |
217 | |
218 | boost::shared_mutex rw_mutex; |
219 | unsigned unblocked_count=0; |
220 | unsigned simultaneous_running_readers=0; |
221 | unsigned max_simultaneous_readers=0; |
222 | unsigned simultaneous_running_writers=0; |
223 | unsigned max_simultaneous_writers=0; |
224 | boost::mutex unblocked_count_mutex; |
225 | boost::condition_variable unblocked_condition; |
226 | boost::mutex finish_reading_mutex; |
227 | boost::unique_lock<boost::mutex> finish_reading_lock(finish_reading_mutex); |
228 | boost::mutex finish_writing_mutex; |
229 | boost::unique_lock<boost::mutex> finish_writing_lock(finish_writing_mutex); |
230 | |
231 | unsigned const reader_count=10; |
232 | unsigned const writer_count=10; |
233 | |
234 | try |
235 | { |
236 | for(unsigned i=0;i<reader_count;++i) |
237 | { |
238 | pool.create_thread(threadfunc: locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, |
239 | finish_reading_mutex,simultaneous_running_readers,max_simultaneous_readers)); |
240 | } |
241 | boost::thread::sleep(xt: delay(secs: 1)); |
242 | for(unsigned i=0;i<writer_count;++i) |
243 | { |
244 | pool.create_thread(threadfunc: locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, |
245 | finish_writing_mutex,simultaneous_running_writers,max_simultaneous_writers)); |
246 | } |
247 | { |
248 | boost::unique_lock<boost::mutex> lk(unblocked_count_mutex); |
249 | while(unblocked_count<reader_count) |
250 | { |
251 | unblocked_condition.wait(m&: lk); |
252 | } |
253 | } |
254 | boost::thread::sleep(xt: delay(secs: 1)); |
255 | CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count); |
256 | |
257 | finish_reading_lock.unlock(); |
258 | |
259 | { |
260 | boost::unique_lock<boost::mutex> lk(unblocked_count_mutex); |
261 | while(unblocked_count<(reader_count+1)) |
262 | { |
263 | unblocked_condition.wait(m&: lk); |
264 | } |
265 | } |
266 | CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1); |
267 | |
268 | finish_writing_lock.unlock(); |
269 | pool.join_all(); |
270 | } |
271 | catch(...) |
272 | { |
273 | pool.interrupt_all(); |
274 | pool.join_all(); |
275 | throw; |
276 | } |
277 | |
278 | CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+writer_count); |
279 | CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_readers,reader_count); |
280 | CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_writers,1u); |
281 | } |
282 | |