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)
6
#define BOOST_THREAD_VERSION 2
8
#include <boost/test/unit_test.hpp>
9
#include <boost/thread/thread.hpp>
10
#include <boost/thread/xtime.hpp>
12
#include "./shared_mutex_locking_thread.hpp"
14
#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
16
boost::unique_lock<boost::mutex> lock(mutex_name); \
17
BOOST_CHECK_EQUAL(value,expected_value); \
20
class simple_upgrade_thread
22
boost::shared_mutex& rwm;
23
boost::mutex& finish_mutex;
24
boost::mutex& unblocked_mutex;
25
unsigned& unblocked_count;
27
void operator=(simple_upgrade_thread&);
30
simple_upgrade_thread(boost::shared_mutex& rwm_,
31
boost::mutex& finish_mutex_,
32
boost::mutex& unblocked_mutex_,
33
unsigned& unblocked_count_):
34
rwm(rwm_),finish_mutex(finish_mutex_),
35
unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
40
boost::upgrade_lock<boost::shared_mutex> lk(rwm);
43
boost::unique_lock<boost::mutex> ulk(unblocked_mutex);
47
boost::unique_lock<boost::mutex> flk(finish_mutex);
52
void test_only_one_upgrade_lock_permitted()
54
unsigned const number_of_threads=2;
56
boost::thread_group pool;
58
boost::shared_mutex rw_mutex;
59
unsigned unblocked_count=0;
60
unsigned simultaneous_running_count=0;
61
unsigned max_simultaneous_running=0;
62
boost::mutex unblocked_count_mutex;
63
boost::condition_variable unblocked_condition;
64
boost::mutex finish_mutex;
65
boost::unique_lock<boost::mutex> finish_lock(finish_mutex);
69
for(unsigned i=0;i<number_of_threads;++i)
71
pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
72
finish_mutex,simultaneous_running_count,max_simultaneous_running));
75
boost::thread::sleep(delay(1));
77
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
90
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
91
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
94
void test_can_lock_upgrade_if_currently_locked_shared()
96
boost::thread_group pool;
98
boost::shared_mutex rw_mutex;
99
unsigned unblocked_count=0;
100
unsigned simultaneous_running_count=0;
101
unsigned max_simultaneous_running=0;
102
boost::mutex unblocked_count_mutex;
103
boost::condition_variable unblocked_condition;
104
boost::mutex finish_mutex;
105
boost::unique_lock<boost::mutex> finish_lock(finish_mutex);
107
unsigned const reader_count=10;
111
for(unsigned i=0;i<reader_count;++i)
113
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
114
finish_mutex,simultaneous_running_count,max_simultaneous_running));
116
boost::thread::sleep(delay(1));
117
pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
118
finish_mutex,simultaneous_running_count,max_simultaneous_running));
120
boost::unique_lock<boost::mutex> lk(unblocked_count_mutex);
121
while(unblocked_count<(reader_count+1))
123
unblocked_condition.wait(lk);
126
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
128
finish_lock.unlock();
133
pool.interrupt_all();
139
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
140
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count+1);
143
void test_can_lock_upgrade_to_unique_if_currently_locked_upgrade()
145
boost::shared_mutex mtx;
146
boost::upgrade_lock<boost::shared_mutex> l(mtx);
147
boost::upgrade_to_unique_lock<boost::shared_mutex> ul(l);
148
BOOST_CHECK(ul.owns_lock());
151
void test_if_other_thread_has_write_lock_try_lock_shared_returns_false()
154
boost::shared_mutex rw_mutex;
155
boost::mutex finish_mutex;
156
boost::mutex unblocked_mutex;
157
unsigned unblocked_count=0;
158
boost::unique_lock<boost::mutex> finish_lock(finish_mutex);
159
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
160
boost::this_thread::sleep(boost::posix_time::seconds(1));
161
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
163
bool const try_succeeded=rw_mutex.try_lock_shared();
164
BOOST_CHECK(!try_succeeded);
167
rw_mutex.unlock_shared();
170
finish_lock.unlock();
174
void test_if_other_thread_has_write_lock_try_lock_upgrade_returns_false()
177
boost::shared_mutex rw_mutex;
178
boost::mutex finish_mutex;
179
boost::mutex unblocked_mutex;
180
unsigned unblocked_count=0;
181
boost::unique_lock<boost::mutex> finish_lock(finish_mutex);
182
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
183
boost::this_thread::sleep(boost::posix_time::seconds(1));
184
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
186
bool const try_succeeded=rw_mutex.try_lock_upgrade();
187
BOOST_CHECK(!try_succeeded);
190
rw_mutex.unlock_upgrade();
193
finish_lock.unlock();
197
void test_if_no_thread_has_lock_try_lock_shared_returns_true()
199
boost::shared_mutex rw_mutex;
200
bool const try_succeeded=rw_mutex.try_lock_shared();
201
BOOST_CHECK(try_succeeded);
204
rw_mutex.unlock_shared();
208
void test_if_no_thread_has_lock_try_lock_upgrade_returns_true()
210
boost::shared_mutex rw_mutex;
211
bool const try_succeeded=rw_mutex.try_lock_upgrade();
212
BOOST_CHECK(try_succeeded);
215
rw_mutex.unlock_upgrade();
219
void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true()
222
boost::shared_mutex rw_mutex;
223
boost::mutex finish_mutex;
224
boost::mutex unblocked_mutex;
225
unsigned unblocked_count=0;
226
boost::unique_lock<boost::mutex> finish_lock(finish_mutex);
227
boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
228
boost::thread::sleep(delay(1));
229
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
231
bool const try_succeeded=rw_mutex.try_lock_shared();
232
BOOST_CHECK(try_succeeded);
235
rw_mutex.unlock_shared();
238
finish_lock.unlock();
242
void test_if_other_thread_has_shared_lock_try_lock_upgrade_returns_true()
245
boost::shared_mutex rw_mutex;
246
boost::mutex finish_mutex;
247
boost::mutex unblocked_mutex;
248
unsigned unblocked_count=0;
249
boost::unique_lock<boost::mutex> finish_lock(finish_mutex);
250
boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
251
boost::thread::sleep(delay(1));
252
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
254
bool const try_succeeded=rw_mutex.try_lock_upgrade();
255
BOOST_CHECK(try_succeeded);
258
rw_mutex.unlock_upgrade();
261
finish_lock.unlock();
265
void test_if_other_thread_has_upgrade_lock_try_lock_upgrade_returns_false()
268
boost::shared_mutex rw_mutex;
269
boost::mutex finish_mutex;
270
boost::mutex unblocked_mutex;
271
unsigned unblocked_count=0;
272
boost::unique_lock<boost::mutex> finish_lock(finish_mutex);
273
boost::thread writer(simple_upgrade_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
274
boost::this_thread::sleep(boost::posix_time::seconds(1));
275
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
277
bool const try_succeeded=rw_mutex.try_lock_upgrade();
278
BOOST_CHECK(!try_succeeded);
281
rw_mutex.unlock_upgrade();
284
finish_lock.unlock();
288
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
290
boost::unit_test::test_suite* test =
291
BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
293
test->add(BOOST_TEST_CASE(&test_only_one_upgrade_lock_permitted));
294
test->add(BOOST_TEST_CASE(&test_can_lock_upgrade_if_currently_locked_shared));
295
test->add(BOOST_TEST_CASE(&test_can_lock_upgrade_to_unique_if_currently_locked_upgrade));
296
test->add(BOOST_TEST_CASE(&test_if_other_thread_has_write_lock_try_lock_shared_returns_false));
297
test->add(BOOST_TEST_CASE(&test_if_no_thread_has_lock_try_lock_shared_returns_true));
298
test->add(BOOST_TEST_CASE(&test_if_other_thread_has_shared_lock_try_lock_shared_returns_true));