• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
19 template<typename Mutex,typename Lock>
20 struct test_initially_locked
21 {
operator ()test_initially_locked22     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 
32 template<typename Mutex,typename Lock>
33 struct 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 
test_initially_unlocked_if_other_thread_has_locktest_initially_unlocked_if_other_thread_has_lock41     test_initially_unlocked_if_other_thread_has_lock():
42         done(false),locked(false)
43     {}
44 
locking_threadtest_initially_unlocked_if_other_thread_has_lock45     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 
is_donetest_initially_unlocked_if_other_thread_has_lock55     bool is_done() const
56     {
57         return done;
58     }
59 
60 
operator ()test_initially_unlocked_if_other_thread_has_lock61     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 
90 template<typename Mutex,typename Lock>
91 struct 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 
test_initially_unlocked_with_try_lock_if_other_thread_has_unique_locktest_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock99     test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock():
100         done(false),locked(false)
101     {}
102 
locking_threadtest_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock103     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 
is_donetest_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock113     bool is_done() const
114     {
115         return done;
116     }
117 
118 
operator ()test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock119     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 
148 template<typename Mutex,typename Lock>
149 struct 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 
test_initially_locked_if_other_thread_has_shared_locktest_initially_locked_if_other_thread_has_shared_lock157     test_initially_locked_if_other_thread_has_shared_lock():
158         done(false),locked(false)
159     {}
160 
locking_threadtest_initially_locked_if_other_thread_has_shared_lock161     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 
is_donetest_initially_locked_if_other_thread_has_shared_lock171     bool is_done() const
172     {
173         return done;
174     }
175 
176 
operator ()test_initially_locked_if_other_thread_has_shared_lock177     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 
206 template<typename Mutex,typename Lock>
207 struct test_initially_unlocked_with_defer_lock_parameter
208 {
operator ()test_initially_unlocked_with_defer_lock_parameter209     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 
219 template<typename Mutex,typename Lock>
220 struct test_initially_locked_with_adopt_lock_parameter
221 {
operator ()test_initially_locked_with_adopt_lock_parameter222     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 };
232 template<typename Mutex,typename Lock>
233 struct test_initially_lock_shared_with_adopt_lock_parameter
234 {
operator ()test_initially_lock_shared_with_adopt_lock_parameter235     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 
247 template<typename Mutex,typename Lock>
248 struct test_unlocked_after_unlock_called
249 {
operator ()test_unlocked_after_unlock_called250     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 
260 template<typename Mutex,typename Lock>
261 struct test_locked_after_lock_called
262 {
operator ()test_locked_after_lock_called263     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 
273 template<typename Mutex,typename Lock>
274 struct test_locked_after_try_lock_called
275 {
operator ()test_locked_after_try_lock_called276     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 
286 template<typename Mutex,typename Lock>
287 struct 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 
test_unlocked_after_try_lock_if_other_thread_has_locktest_unlocked_after_try_lock_if_other_thread_has_lock295     test_unlocked_after_try_lock_if_other_thread_has_lock():
296         done(false),locked(false)
297     {}
298 
locking_threadtest_unlocked_after_try_lock_if_other_thread_has_lock299     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 
is_donetest_unlocked_after_try_lock_if_other_thread_has_lock309     bool is_done() const
310     {
311         return done;
312     }
313 
314 
operator ()test_unlocked_after_try_lock_if_other_thread_has_lock315     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 
344 template<typename Mutex,typename Lock>
345 struct test_throws_if_lock_called_when_already_locked
346 {
operator ()test_throws_if_lock_called_when_already_locked347     void operator()() const
348     {
349         Mutex m;
350         Lock lock(m);
351 
352         BOOST_CHECK_THROW( lock.lock(), boost::lock_error );
353     }
354 };
355 
356 template<typename Mutex,typename Lock>
357 struct test_throws_if_try_lock_called_when_already_locked
358 {
operator ()test_throws_if_try_lock_called_when_already_locked359     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 
368 template<typename Mutex,typename Lock>
369 struct test_throws_if_unlock_called_when_already_unlocked
370 {
operator ()test_throws_if_unlock_called_when_already_unlocked371     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 };
380 template<typename Lock>
381 struct test_default_constructed_has_no_mutex_and_unlocked
382 {
operator ()test_default_constructed_has_no_mutex_and_unlocked383     void operator()() const
384     {
385         Lock l;
386         BOOST_CHECK(!l.mutex());
387         BOOST_CHECK(!l.owns_lock());
388     }
389 };
390 
391 
392 template<typename Mutex,typename Lock>
393 struct test_locks_can_be_swapped
394 {
operator ()test_locks_can_be_swapped395     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 
426 template<typename Mutex,typename Lock>
test_lock_is_scoped_lock_concept_for_mutex()427 void 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 
443 typedef boost::mpl::vector<boost::mutex,boost::timed_mutex,
444     boost::recursive_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_lock;
445 
BOOST_AUTO_TEST_CASE_TEMPLATE(test_scoped_lock_concept,Mutex,mutex_types_with_scoped_lock)446 BOOST_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 
453 typedef boost::mpl::vector<boost::mutex,boost::timed_mutex,
454     boost::recursive_mutex,boost::recursive_timed_mutex,boost::shared_mutex> all_mutex_types;
455 
BOOST_AUTO_TEST_CASE_TEMPLATE(test_unique_lock_is_scoped_lock,Mutex,all_mutex_types)456 BOOST_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 
463 typedef 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 
BOOST_AUTO_TEST_CASE_TEMPLATE(test_scoped_try_lock_concept,Mutex,mutex_types_with_scoped_try_lock)466 BOOST_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 
485 struct 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 
dummy_shared_mutexdummy_shared_mutex495     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 
lockdummy_shared_mutex503     void lock()
504     {
505         locked=true;
506     }
507 
lock_shareddummy_shared_mutex508     void lock_shared()
509     {
510         shared_locked=true;
511     }
512 
unlockdummy_shared_mutex513     void unlock()
514     {}
515 
unlock_shareddummy_shared_mutex516     void unlock_shared()
517     {
518         shared_unlocked=true;
519     }
520 
timed_lock_shareddummy_shared_mutex521     bool timed_lock_shared(boost::system_time)
522     {
523         shared_timed_locked_absolute=true;
524         return false;
525     }
526     template<typename Duration>
timed_lock_shareddummy_shared_mutex527     bool timed_lock_shared(Duration)
528     {
529         shared_timed_locked_relative=true;
530         return false;
531     }
timed_lockdummy_shared_mutex532     bool timed_lock(boost::system_time)
533     {
534         timed_locked_absolute=true;
535         return false;
536     }
537     template<typename Duration>
timed_lockdummy_shared_mutex538     bool timed_lock(Duration)
539     {
540         timed_locked_relative=true;
541         return false;
542     }
543 
544 };
545 
546 
BOOST_AUTO_TEST_CASE(test_shared_lock)547 BOOST_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(boost::posix_time::milliseconds(5));
572     BOOST_CHECK(dummy.shared_timed_locked_relative);
573     lk.timed_lock(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