1// (C) Copyright 2006-8 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: lock_concept test suite
8
9#include <boost/test/unit_test.hpp>
10#include <boost/test/test_case_template.hpp>
11#include <boost/mpl/vector.hpp>
12#include <boost/thread/mutex.hpp>
13#include <boost/thread/lock_types.hpp>
14#include <boost/thread/shared_mutex.hpp>
15#include <boost/thread/thread_only.hpp>
16#include <boost/thread/recursive_mutex.hpp>
17#include <boost/thread/condition_variable.hpp>
18
19template<typename Mutex,typename Lock>
20struct test_initially_locked
21{
22 void operator()() const
23 {
24 Mutex m;
25 Lock lock(m);
26
27 BOOST_CHECK(lock);
28 BOOST_CHECK(lock.owns_lock());
29 }
30};
31
32template<typename Mutex,typename Lock>
33struct test_initially_unlocked_if_other_thread_has_lock
34{
35 Mutex m;
36 boost::mutex done_mutex;
37 bool done;
38 bool locked;
39 boost::condition_variable done_cond;
40
41 test_initially_unlocked_if_other_thread_has_lock():
42 done(false),locked(false)
43 {}
44
45 void locking_thread()
46 {
47 Lock lock(m);
48
49 boost::lock_guard<boost::mutex> lk(done_mutex);
50 locked=lock.owns_lock();
51 done=true;
52 done_cond.notify_one();
53 }
54
55 bool is_done() const
56 {
57 return done;
58 }
59
60
61 void operator()()
62 {
63 Lock lock(m);
64
65 typedef test_initially_unlocked_if_other_thread_has_lock<Mutex,Lock> this_type;
66
67 boost::thread t(&this_type::locking_thread,this);
68
69 try
70 {
71 {
72 boost::unique_lock<boost::mutex> lk(done_mutex);
73 BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
74 boost::bind(&this_type::is_done,this)));
75 BOOST_CHECK(!locked);
76 }
77
78 lock.unlock();
79 t.join();
80 }
81 catch(...)
82 {
83 lock.unlock();
84 t.join();
85 throw;
86 }
87 }
88};
89
90template<typename Mutex,typename Lock>
91struct test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock
92{
93 Mutex m;
94 boost::mutex done_mutex;
95 bool done;
96 bool locked;
97 boost::condition_variable done_cond;
98
99 test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock():
100 done(false),locked(false)
101 {}
102
103 void locking_thread()
104 {
105 Lock lock(m,boost::try_to_lock);
106
107 boost::lock_guard<boost::mutex> lk(done_mutex);
108 locked=lock.owns_lock();
109 done=true;
110 done_cond.notify_one();
111 }
112
113 bool is_done() const
114 {
115 return done;
116 }
117
118
119 void operator()()
120 {
121 boost::unique_lock<Mutex> lock(m);
122
123 typedef test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock<Mutex,Lock> this_type;
124
125 boost::thread t(&this_type::locking_thread,this);
126
127 try
128 {
129 {
130 boost::unique_lock<boost::mutex> lk(done_mutex);
131 BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
132 boost::bind(&this_type::is_done,this)));
133 BOOST_CHECK(!locked);
134 }
135
136 lock.unlock();
137 t.join();
138 }
139 catch(...)
140 {
141 lock.unlock();
142 t.join();
143 throw;
144 }
145 }
146};
147
148template<typename Mutex,typename Lock>
149struct test_initially_locked_if_other_thread_has_shared_lock
150{
151 Mutex m;
152 boost::mutex done_mutex;
153 bool done;
154 bool locked;
155 boost::condition_variable done_cond;
156
157 test_initially_locked_if_other_thread_has_shared_lock():
158 done(false),locked(false)
159 {}
160
161 void locking_thread()
162 {
163 Lock lock(m);
164
165 boost::lock_guard<boost::mutex> lk(done_mutex);
166 locked=lock.owns_lock();
167 done=true;
168 done_cond.notify_one();
169 }
170
171 bool is_done() const
172 {
173 return done;
174 }
175
176
177 void operator()()
178 {
179 boost::shared_lock<Mutex> lock(m);
180
181 typedef test_initially_locked_if_other_thread_has_shared_lock<Mutex,Lock> this_type;
182
183 boost::thread t(&this_type::locking_thread,this);
184
185 try
186 {
187 {
188 boost::unique_lock<boost::mutex> lk(done_mutex);
189 BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
190 boost::bind(&this_type::is_done,this)));
191 BOOST_CHECK(locked);
192 }
193
194 lock.unlock();
195 t.join();
196 }
197 catch(...)
198 {
199 lock.unlock();
200 t.join();
201 throw;
202 }
203 }
204};
205
206template<typename Mutex,typename Lock>
207struct test_initially_unlocked_with_defer_lock_parameter
208{
209 void operator()() const
210 {
211 Mutex m;
212 Lock lock(m,boost::defer_lock);
213
214 BOOST_CHECK(!lock);
215 BOOST_CHECK(!lock.owns_lock());
216 }
217};
218
219template<typename Mutex,typename Lock>
220struct test_initially_locked_with_adopt_lock_parameter
221{
222 void operator()() const
223 {
224 Mutex m;
225 m.lock();
226 Lock lock(m,boost::adopt_lock);
227
228 BOOST_CHECK(lock);
229 BOOST_CHECK(lock.owns_lock());
230 }
231};
232template<typename Mutex,typename Lock>
233struct test_initially_lock_shared_with_adopt_lock_parameter
234{
235 void operator()() const
236 {
237 Mutex m;
238 m.lock_shared();
239 Lock lock(m,boost::adopt_lock);
240
241 BOOST_CHECK(lock);
242 BOOST_CHECK(lock.owns_lock());
243 }
244};
245
246
247template<typename Mutex,typename Lock>
248struct test_unlocked_after_unlock_called
249{
250 void operator()() const
251 {
252 Mutex m;
253 Lock lock(m);
254 lock.unlock();
255 BOOST_CHECK(!lock);
256 BOOST_CHECK(!lock.owns_lock());
257 }
258};
259
260template<typename Mutex,typename Lock>
261struct test_locked_after_lock_called
262{
263 void operator()() const
264 {
265 Mutex m;
266 Lock lock(m,boost::defer_lock);
267 lock.lock();
268 BOOST_CHECK(lock);
269 BOOST_CHECK(lock.owns_lock());
270 }
271};
272
273template<typename Mutex,typename Lock>
274struct test_locked_after_try_lock_called
275{
276 void operator()() const
277 {
278 Mutex m;
279 Lock lock(m,boost::defer_lock);
280 lock.try_lock();
281 BOOST_CHECK(lock);
282 BOOST_CHECK(lock.owns_lock());
283 }
284};
285
286template<typename Mutex,typename Lock>
287struct test_unlocked_after_try_lock_if_other_thread_has_lock
288{
289 Mutex m;
290 boost::mutex done_mutex;
291 bool done;
292 bool locked;
293 boost::condition_variable done_cond;
294
295 test_unlocked_after_try_lock_if_other_thread_has_lock():
296 done(false),locked(false)
297 {}
298
299 void locking_thread()
300 {
301 Lock lock(m,boost::defer_lock);
302
303 boost::lock_guard<boost::mutex> lk(done_mutex);
304 locked=lock.owns_lock();
305 done=true;
306 done_cond.notify_one();
307 }
308
309 bool is_done() const
310 {
311 return done;
312 }
313
314
315 void operator()()
316 {
317 Lock lock(m);
318
319 typedef test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock> this_type;
320
321 boost::thread t(&this_type::locking_thread,this);
322
323 try
324 {
325 {
326 boost::unique_lock<boost::mutex> lk(done_mutex);
327 BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
328 boost::bind(&this_type::is_done,this)));
329 BOOST_CHECK(!locked);
330 }
331
332 lock.unlock();
333 t.join();
334 }
335 catch(...)
336 {
337 lock.unlock();
338 t.join();
339 throw;
340 }
341 }
342};
343
344template<typename Mutex,typename Lock>
345struct test_throws_if_lock_called_when_already_locked
346{
347 void operator()() const
348 {
349 Mutex m;
350 Lock lock(m);
351
352 BOOST_CHECK_THROW( lock.lock(), boost::lock_error );
353 }
354};
355
356template<typename Mutex,typename Lock>
357struct test_throws_if_try_lock_called_when_already_locked
358{
359 void operator()() const
360 {
361 Mutex m;
362 Lock lock(m);
363
364 BOOST_CHECK_THROW( lock.try_lock(), boost::lock_error );
365 }
366};
367
368template<typename Mutex,typename Lock>
369struct test_throws_if_unlock_called_when_already_unlocked
370{
371 void operator()() const
372 {
373 Mutex m;
374 Lock lock(m);
375 lock.unlock();
376
377 BOOST_CHECK_THROW( lock.unlock(), boost::lock_error );
378 }
379};
380template<typename Lock>
381struct test_default_constructed_has_no_mutex_and_unlocked
382{
383 void operator()() const
384 {
385 Lock l;
386 BOOST_CHECK(!l.mutex());
387 BOOST_CHECK(!l.owns_lock());
388 }
389};
390
391
392template<typename Mutex,typename Lock>
393struct test_locks_can_be_swapped
394{
395 void operator()() const
396 {
397 Mutex m1;
398 Mutex m2;
399 Mutex m3;
400
401 Lock l1(m1);
402 Lock l2(m2);
403
404 BOOST_CHECK_EQUAL(l1.mutex(),&m1);
405 BOOST_CHECK_EQUAL(l2.mutex(),&m2);
406
407 l1.swap(l2);
408
409 BOOST_CHECK_EQUAL(l1.mutex(),&m2);
410 BOOST_CHECK_EQUAL(l2.mutex(),&m1);
411
412 swap(l1,l2);
413
414 BOOST_CHECK_EQUAL(l1.mutex(),&m1);
415 BOOST_CHECK_EQUAL(l2.mutex(),&m2);
416
417#if 0
418 l1.swap(Lock(m3));
419
420 BOOST_CHECK_EQUAL(l1.mutex(),&m3);
421#endif
422
423 }
424};
425
426template<typename Mutex,typename Lock>
427void test_lock_is_scoped_lock_concept_for_mutex()
428{
429 test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
430 test_initially_locked<Mutex,Lock>()();
431 test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
432 test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
433 test_unlocked_after_unlock_called<Mutex,Lock>()();
434 test_locked_after_lock_called<Mutex,Lock>()();
435 test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
436 test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
437 test_locks_can_be_swapped<Mutex,Lock>()();
438 test_locked_after_try_lock_called<Mutex,Lock>()();
439 test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
440 test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock>()();
441}
442
443typedef boost::mpl::vector<boost::mutex,boost::timed_mutex,
444 boost::recursive_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_lock;
445
446BOOST_AUTO_TEST_CASE_TEMPLATE(test_scoped_lock_concept,Mutex,mutex_types_with_scoped_lock)
447{
448 typedef typename Mutex::scoped_lock Lock;
449
450 test_lock_is_scoped_lock_concept_for_mutex<Mutex,Lock>();
451}
452
453typedef boost::mpl::vector<boost::mutex,boost::timed_mutex,
454 boost::recursive_mutex,boost::recursive_timed_mutex,boost::shared_mutex> all_mutex_types;
455
456BOOST_AUTO_TEST_CASE_TEMPLATE(test_unique_lock_is_scoped_lock,Mutex,all_mutex_types)
457{
458 typedef boost::unique_lock<Mutex> Lock;
459
460 test_lock_is_scoped_lock_concept_for_mutex<Mutex,Lock>();
461}
462
463typedef boost::mpl::vector<boost::try_mutex,boost::timed_mutex,
464 boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_try_lock;
465
466BOOST_AUTO_TEST_CASE_TEMPLATE(test_scoped_try_lock_concept,Mutex,mutex_types_with_scoped_try_lock)
467{
468 typedef typename Mutex::scoped_try_lock Lock;
469
470 test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
471 test_initially_locked<Mutex,Lock>()();
472 test_initially_unlocked_if_other_thread_has_lock<Mutex,Lock>()();
473 test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
474 test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
475 test_unlocked_after_unlock_called<Mutex,Lock>()();
476 test_locked_after_lock_called<Mutex,Lock>()();
477 test_locked_after_try_lock_called<Mutex,Lock>()();
478 test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock>()();
479 test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
480 test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
481 test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
482 test_locks_can_be_swapped<Mutex,Lock>()();
483}
484
485struct dummy_shared_mutex
486{
487 bool locked;
488 bool shared_locked;
489 bool shared_unlocked;
490 bool shared_timed_locked_relative;
491 bool shared_timed_locked_absolute;
492 bool timed_locked_relative;
493 bool timed_locked_absolute;
494
495 dummy_shared_mutex():
496 locked(false),shared_locked(false),shared_unlocked(false),
497 shared_timed_locked_relative(false),
498 shared_timed_locked_absolute(false),
499 timed_locked_relative(false),
500 timed_locked_absolute(false)
501 {}
502
503 void lock()
504 {
505 locked=true;
506 }
507
508 void lock_shared()
509 {
510 shared_locked=true;
511 }
512
513 void unlock()
514 {}
515
516 void unlock_shared()
517 {
518 shared_unlocked=true;
519 }
520
521 bool timed_lock_shared(boost::system_time)
522 {
523 shared_timed_locked_absolute=true;
524 return false;
525 }
526 template<typename Duration>
527 bool timed_lock_shared(Duration)
528 {
529 shared_timed_locked_relative=true;
530 return false;
531 }
532 bool timed_lock(boost::system_time)
533 {
534 timed_locked_absolute=true;
535 return false;
536 }
537 template<typename Duration>
538 bool timed_lock(Duration)
539 {
540 timed_locked_relative=true;
541 return false;
542 }
543
544};
545
546
547BOOST_AUTO_TEST_CASE(test_shared_lock)
548{
549 typedef boost::shared_mutex Mutex;
550 typedef boost::shared_lock<Mutex> Lock;
551
552 test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
553 test_initially_locked<Mutex,Lock>()();
554 test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock<Mutex,Lock>()();
555 test_initially_locked_if_other_thread_has_shared_lock<Mutex,Lock>()();
556 test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
557 test_initially_lock_shared_with_adopt_lock_parameter<Mutex,Lock>()();
558 test_unlocked_after_unlock_called<Mutex,Lock>()();
559 test_locked_after_lock_called<Mutex,Lock>()();
560 test_locked_after_try_lock_called<Mutex,Lock>()();
561 test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
562 test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
563 test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
564 test_locks_can_be_swapped<Mutex,Lock>()();
565
566 dummy_shared_mutex dummy;
567 boost::shared_lock<dummy_shared_mutex> lk(dummy);
568 BOOST_CHECK(dummy.shared_locked);
569 lk.unlock();
570 BOOST_CHECK(dummy.shared_unlocked);
571 lk.timed_lock(target_time: boost::posix_time::milliseconds(5));
572 BOOST_CHECK(dummy.shared_timed_locked_relative);
573 lk.timed_lock(target_time: boost::get_system_time());
574 BOOST_CHECK(dummy.shared_timed_locked_absolute);
575}
576
577//boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
578//{
579// boost::unit_test::test_suite* test =
580// BOOST_TEST_SUITE("Boost.Threads: lock concept test suite");
581//
582// typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,
583// boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_lock;
584//
585// test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_lock_concept,mutex_types_with_scoped_lock));
586//
587// typedef boost::mpl::vector<boost::try_mutex,boost::timed_mutex,
588// boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_try_lock;
589//
590// test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_try_lock_concept,mutex_types_with_scoped_try_lock));
591//
592// typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,
593// boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex,boost::shared_mutex> all_mutex_types;
594//
595// test->add(BOOST_TEST_CASE_TEMPLATE(test_unique_lock_is_scoped_lock,all_mutex_types));
596// test->add(BOOST_TEST_CASE(&test_shared_lock));
597//
598// return test;
599//}
600
601

source code of boost/libs/thread/test/test_lock_concept.cpp