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