1// (C) Copyright 2008 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
8#define BOOST_TEST_MODULE Boost.Threads: generic locks test suite
9
10#include <boost/test/unit_test.hpp>
11#include <boost/thread/mutex.hpp>
12#include <boost/thread/thread_only.hpp>
13#include <boost/thread/locks.hpp>
14#include <boost/thread/condition_variable.hpp>
15#include <iterator>
16#include <cstddef>
17
18BOOST_AUTO_TEST_CASE(test_lock_two_uncontended)
19{
20 boost::mutex m1,m2;
21
22 boost::unique_lock<boost::mutex> l1(m1,boost::defer_lock),
23 l2(m2,boost::defer_lock);
24
25 BOOST_CHECK(!l1.owns_lock());
26 BOOST_CHECK(!l2.owns_lock());
27
28 boost::lock(m1&: l1,m2&: l2);
29
30 BOOST_CHECK(l1.owns_lock());
31 BOOST_CHECK(l2.owns_lock());
32}
33
34struct wait_data
35{
36 boost::mutex m;
37 bool flag;
38 boost::condition_variable cond;
39
40 wait_data():
41 flag(false)
42 {}
43
44 void wait()
45 {
46 boost::unique_lock<boost::mutex> l(m);
47 while(!flag)
48 {
49 cond.wait(m&: l);
50 }
51 }
52
53 template<typename Duration>
54 bool timed_wait(Duration d)
55 {
56 boost::system_time const target=boost::get_system_time()+d;
57
58 boost::unique_lock<boost::mutex> l(m);
59 while(!flag)
60 {
61 if(!cond.timed_wait(m&: l,abs_time: target))
62 {
63 return flag;
64 }
65 }
66 return true;
67 }
68
69 void signal()
70 {
71 boost::unique_lock<boost::mutex> l(m);
72 flag=true;
73 cond.notify_all();
74 }
75};
76
77
78void lock_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,wait_data* locked,wait_data* quit)
79{
80 boost::lock_guard<boost::mutex> l1(*m1);
81 boost::this_thread::sleep(rel_time: boost::posix_time::milliseconds(500));
82 boost::lock_guard<boost::mutex> l2(*m2);
83 locked->signal();
84 quit->wait();
85}
86
87void lock_pair(boost::mutex* m1,boost::mutex* m2)
88{
89 boost::lock(m1&: *m1,m2&: *m2);
90 boost::unique_lock<boost::mutex> l1(*m1,boost::adopt_lock),
91 l2(*m2,boost::adopt_lock);
92}
93
94BOOST_AUTO_TEST_CASE(test_lock_two_other_thread_locks_in_order)
95{
96 boost::mutex m1,m2;
97 wait_data locked;
98 wait_data release;
99
100 boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release);
101 boost::this_thread::sleep(rel_time: boost::posix_time::milliseconds(10));
102
103 boost::thread t2(lock_pair,&m1,&m2);
104 BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1)));
105
106 release.signal();
107
108 BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1)));
109
110 t.join();
111}
112
113BOOST_AUTO_TEST_CASE(test_lock_two_other_thread_locks_in_opposite_order)
114{
115 boost::mutex m1,m2;
116 wait_data locked;
117 wait_data release;
118
119 boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release);
120 boost::this_thread::sleep(rel_time: boost::posix_time::milliseconds(10));
121
122 boost::thread t2(lock_pair,&m2,&m1);
123 BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1)));
124
125 release.signal();
126
127 BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1)));
128
129 t.join();
130}
131
132BOOST_AUTO_TEST_CASE(test_lock_five_uncontended)
133{
134 boost::mutex m1,m2,m3,m4,m5;
135
136 boost::unique_lock<boost::mutex> l1(m1,boost::defer_lock),
137 l2(m2,boost::defer_lock),
138 l3(m3,boost::defer_lock),
139 l4(m4,boost::defer_lock),
140 l5(m5,boost::defer_lock);
141
142 BOOST_CHECK(!l1.owns_lock());
143 BOOST_CHECK(!l2.owns_lock());
144 BOOST_CHECK(!l3.owns_lock());
145 BOOST_CHECK(!l4.owns_lock());
146 BOOST_CHECK(!l5.owns_lock());
147
148 boost::lock(m1&: l1,m2&: l2,m3&: l3,m4&: l4,m5&: l5);
149
150 BOOST_CHECK(l1.owns_lock());
151 BOOST_CHECK(l2.owns_lock());
152 BOOST_CHECK(l3.owns_lock());
153 BOOST_CHECK(l4.owns_lock());
154 BOOST_CHECK(l5.owns_lock());
155}
156
157void lock_five_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5,
158 wait_data* locked,wait_data* quit)
159{
160 boost::lock_guard<boost::mutex> l1(*m1);
161 boost::this_thread::sleep(rel_time: boost::posix_time::milliseconds(500));
162 boost::lock_guard<boost::mutex> l2(*m2);
163 boost::this_thread::sleep(rel_time: boost::posix_time::milliseconds(500));
164 boost::lock_guard<boost::mutex> l3(*m3);
165 boost::this_thread::sleep(rel_time: boost::posix_time::milliseconds(500));
166 boost::lock_guard<boost::mutex> l4(*m4);
167 boost::this_thread::sleep(rel_time: boost::posix_time::milliseconds(500));
168 boost::lock_guard<boost::mutex> l5(*m5);
169 locked->signal();
170 quit->wait();
171}
172
173void lock_five(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5)
174{
175 boost::lock(m1&: *m1,m2&: *m2,m3&: *m3,m4&: *m4,m5&: *m5);
176 m1->unlock();
177 m2->unlock();
178 m3->unlock();
179 m4->unlock();
180 m5->unlock();
181}
182
183BOOST_AUTO_TEST_CASE(test_lock_five_other_thread_locks_in_order)
184{
185 boost::mutex m1,m2,m3,m4,m5;
186 wait_data locked;
187 wait_data release;
188
189 boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release);
190 boost::this_thread::sleep(rel_time: boost::posix_time::milliseconds(10));
191
192 boost::thread t2(lock_five,&m1,&m2,&m3,&m4,&m5);
193 BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
194
195 release.signal();
196
197 BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
198
199 t.join();
200}
201
202BOOST_AUTO_TEST_CASE(test_lock_five_other_thread_locks_in_different_order)
203{
204 boost::mutex m1,m2,m3,m4,m5;
205 wait_data locked;
206 wait_data release;
207
208 boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release);
209 boost::this_thread::sleep(rel_time: boost::posix_time::milliseconds(10));
210
211 boost::thread t2(lock_five,&m5,&m1,&m4,&m2,&m3);
212 BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
213
214 release.signal();
215
216 BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
217
218 t.join();
219}
220
221void lock_n(boost::mutex* mutexes,unsigned count)
222{
223 boost::lock(m1&: mutexes,m2: mutexes+count);
224 for(unsigned i=0;i<count;++i)
225 {
226 mutexes[i].unlock();
227 }
228}
229
230
231BOOST_AUTO_TEST_CASE(test_lock_ten_other_thread_locks_in_different_order)
232{
233 unsigned const num_mutexes=10;
234
235 boost::mutex mutexes[num_mutexes];
236 wait_data locked;
237 wait_data release;
238
239 boost::thread t(lock_five_mutexes_slowly,&mutexes[6],&mutexes[3],&mutexes[8],&mutexes[0],&mutexes[2],&locked,&release);
240 boost::this_thread::sleep(rel_time: boost::posix_time::milliseconds(10));
241
242 boost::thread t2(lock_n,mutexes,num_mutexes);
243 BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
244
245 release.signal();
246
247 BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
248
249 t.join();
250}
251
252struct dummy_mutex
253{
254 bool is_locked;
255
256 dummy_mutex():
257 is_locked(false)
258 {}
259
260 void lock()
261 {
262 is_locked=true;
263 }
264
265 bool try_lock()
266 {
267 if(is_locked)
268 {
269 return false;
270 }
271 is_locked=true;
272 return true;
273 }
274
275 void unlock()
276 {
277 is_locked=false;
278 }
279};
280
281namespace boost
282{
283 template<>
284 struct is_mutex_type<dummy_mutex>
285 {
286 BOOST_STATIC_CONSTANT(bool, value = true);
287 };
288}
289
290
291
292BOOST_AUTO_TEST_CASE(test_lock_five_in_range)
293{
294 unsigned const num_mutexes=5;
295 dummy_mutex mutexes[num_mutexes];
296
297 boost::lock(m1&: mutexes,m2: mutexes+num_mutexes);
298
299 for(unsigned i=0;i<num_mutexes;++i)
300 {
301 BOOST_CHECK(mutexes[i].is_locked);
302 }
303}
304
305class dummy_iterator
306{
307private:
308 dummy_mutex* p;
309public:
310 typedef std::forward_iterator_tag iterator_category;
311 typedef dummy_mutex value_type;
312 typedef std::ptrdiff_t difference_type;
313 typedef dummy_mutex* pointer;
314 typedef dummy_mutex& reference;
315
316 explicit dummy_iterator(dummy_mutex* p_):
317 p(p_)
318 {}
319
320 bool operator==(dummy_iterator const& other) const
321 {
322 return p==other.p;
323 }
324
325 bool operator!=(dummy_iterator const& other) const
326 {
327 return p!=other.p;
328 }
329
330 bool operator<(dummy_iterator const& other) const
331 {
332 return p<other.p;
333 }
334
335 dummy_mutex& operator*() const
336 {
337 return *p;
338 }
339
340 dummy_mutex* operator->() const
341 {
342 return p;
343 }
344
345 dummy_iterator operator++(int)
346 {
347 dummy_iterator temp(*this);
348 ++p;
349 return temp;
350 }
351
352 dummy_iterator& operator++()
353 {
354 ++p;
355 return *this;
356 }
357
358};
359
360
361BOOST_AUTO_TEST_CASE(test_lock_five_in_range_custom_iterator)
362{
363 unsigned const num_mutexes=5;
364 dummy_mutex mutexes[num_mutexes];
365
366 boost::lock(m1: dummy_iterator(mutexes),m2: dummy_iterator(mutexes+num_mutexes));
367
368 for(unsigned i=0;i<num_mutexes;++i)
369 {
370 BOOST_CHECK(mutexes[i].is_locked);
371 }
372}
373
374class dummy_mutex2:
375 public dummy_mutex
376{};
377
378
379BOOST_AUTO_TEST_CASE(test_lock_ten_in_range_inherited_mutex)
380{
381 unsigned const num_mutexes=10;
382 dummy_mutex2 mutexes[num_mutexes];
383
384 boost::lock(m1&: mutexes,m2: mutexes+num_mutexes);
385
386 for(unsigned i=0;i<num_mutexes;++i)
387 {
388 BOOST_CHECK(mutexes[i].is_locked);
389 }
390}
391
392BOOST_AUTO_TEST_CASE(test_try_lock_two_uncontended)
393{
394 dummy_mutex m1,m2;
395
396 int const res=boost::try_lock(m1,m2);
397
398 BOOST_CHECK(res==-1);
399 BOOST_CHECK(m1.is_locked);
400 BOOST_CHECK(m2.is_locked);
401}
402BOOST_AUTO_TEST_CASE(test_try_lock_two_first_locked)
403{
404 dummy_mutex m1,m2;
405 m1.lock();
406
407 boost::unique_lock<dummy_mutex> l1(m1,boost::defer_lock),
408 l2(m2,boost::defer_lock);
409
410 int const res=boost::try_lock(m1&: l1,m2&: l2);
411
412 BOOST_CHECK(res==0);
413 BOOST_CHECK(m1.is_locked);
414 BOOST_CHECK(!m2.is_locked);
415 BOOST_CHECK(!l1.owns_lock());
416 BOOST_CHECK(!l2.owns_lock());
417}
418BOOST_AUTO_TEST_CASE(test_try_lock_two_second_locked)
419{
420 dummy_mutex m1,m2;
421 m2.lock();
422
423 boost::unique_lock<dummy_mutex> l1(m1,boost::defer_lock),
424 l2(m2,boost::defer_lock);
425
426 int const res=boost::try_lock(m1&: l1,m2&: l2);
427
428 BOOST_CHECK(res==1);
429 BOOST_CHECK(!m1.is_locked);
430 BOOST_CHECK(m2.is_locked);
431 BOOST_CHECK(!l1.owns_lock());
432 BOOST_CHECK(!l2.owns_lock());
433}
434
435BOOST_AUTO_TEST_CASE(test_try_lock_three)
436{
437 int const num_mutexes=3;
438
439 for(int i=-1;i<num_mutexes;++i)
440 {
441 dummy_mutex mutexes[num_mutexes];
442
443 if(i>=0)
444 {
445 mutexes[i].lock();
446 }
447 boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
448 l2(mutexes[1],boost::defer_lock),
449 l3(mutexes[2],boost::defer_lock);
450
451 int const res=boost::try_lock(m1&: l1,m2&: l2,m3&: l3);
452
453 BOOST_CHECK(res==i);
454 for(int j=0;j<num_mutexes;++j)
455 {
456 if((i==j) || (i==-1))
457 {
458 BOOST_CHECK(mutexes[j].is_locked);
459 }
460 else
461 {
462 BOOST_CHECK(!mutexes[j].is_locked);
463 }
464 }
465 if(i==-1)
466 {
467 BOOST_CHECK(l1.owns_lock());
468 BOOST_CHECK(l2.owns_lock());
469 BOOST_CHECK(l3.owns_lock());
470 }
471 else
472 {
473 BOOST_CHECK(!l1.owns_lock());
474 BOOST_CHECK(!l2.owns_lock());
475 BOOST_CHECK(!l3.owns_lock());
476 }
477 }
478}
479
480BOOST_AUTO_TEST_CASE(test_try_lock_four)
481{
482 int const num_mutexes=4;
483
484 for(int i=-1;i<num_mutexes;++i)
485 {
486 dummy_mutex mutexes[num_mutexes];
487
488 if(i>=0)
489 {
490 mutexes[i].lock();
491 }
492 boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
493 l2(mutexes[1],boost::defer_lock),
494 l3(mutexes[2],boost::defer_lock),
495 l4(mutexes[3],boost::defer_lock);
496
497 int const res=boost::try_lock(m1&: l1,m2&: l2,m3&: l3,m4&: l4);
498
499 BOOST_CHECK(res==i);
500 for(int j=0;j<num_mutexes;++j)
501 {
502 if((i==j) || (i==-1))
503 {
504 BOOST_CHECK(mutexes[j].is_locked);
505 }
506 else
507 {
508 BOOST_CHECK(!mutexes[j].is_locked);
509 }
510 }
511 if(i==-1)
512 {
513 BOOST_CHECK(l1.owns_lock());
514 BOOST_CHECK(l2.owns_lock());
515 BOOST_CHECK(l3.owns_lock());
516 BOOST_CHECK(l4.owns_lock());
517 }
518 else
519 {
520 BOOST_CHECK(!l1.owns_lock());
521 BOOST_CHECK(!l2.owns_lock());
522 BOOST_CHECK(!l3.owns_lock());
523 BOOST_CHECK(!l4.owns_lock());
524 }
525 }
526}
527
528BOOST_AUTO_TEST_CASE(test_try_lock_five)
529{
530 int const num_mutexes=5;
531
532 for(int i=-1;i<num_mutexes;++i)
533 {
534 dummy_mutex mutexes[num_mutexes];
535
536 if(i>=0)
537 {
538 mutexes[i].lock();
539 }
540 boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
541 l2(mutexes[1],boost::defer_lock),
542 l3(mutexes[2],boost::defer_lock),
543 l4(mutexes[3],boost::defer_lock),
544 l5(mutexes[4],boost::defer_lock);
545
546 int const res=boost::try_lock(m1&: l1,m2&: l2,m3&: l3,m4&: l4,m5&: l5);
547
548 BOOST_CHECK(res==i);
549 for(int j=0;j<num_mutexes;++j)
550 {
551 if((i==j) || (i==-1))
552 {
553 BOOST_CHECK(mutexes[j].is_locked);
554 }
555 else
556 {
557 BOOST_CHECK(!mutexes[j].is_locked);
558 }
559 }
560 if(i==-1)
561 {
562 BOOST_CHECK(l1.owns_lock());
563 BOOST_CHECK(l2.owns_lock());
564 BOOST_CHECK(l3.owns_lock());
565 BOOST_CHECK(l4.owns_lock());
566 BOOST_CHECK(l5.owns_lock());
567 }
568 else
569 {
570 BOOST_CHECK(!l1.owns_lock());
571 BOOST_CHECK(!l2.owns_lock());
572 BOOST_CHECK(!l3.owns_lock());
573 BOOST_CHECK(!l4.owns_lock());
574 BOOST_CHECK(!l5.owns_lock());
575 }
576 }
577}
578
579

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