1 // Copyright (C) 2007 Anthony Williams
2 // Copyright (C) 2013 Andrey Semashev
3 //
4 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
5 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 
7 #include <boost/bind.hpp>
8 #include <boost/thread/thread.hpp>
9 #include <boost/test/unit_test.hpp>
10 #include "utils.hpp"
11 #include "condition_test_common.hpp"
12 
13 unsigned const number_of_test_threads = 5;
14 
do_test_condition_notify_all_wakes_from_wait()15 void do_test_condition_notify_all_wakes_from_wait()
16 {
17     wait_for_flag data;
18 
19     boost::thread_group group;
20 
21     try
22     {
23         for(unsigned i=0;i<number_of_test_threads;++i)
24         {
25             group.create_thread(bind(&wait_for_flag::wait_without_predicate, data));
26         }
27 
28         {
29             boost::sync::unique_lock<boost::sync::mutex> lock(data.mutex);
30             data.flag=true;
31             data.cond_var.notify_all();
32         }
33 
34         group.join_all();
35         BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
36     }
37     catch(...)
38     {
39         group.join_all();
40         throw;
41     }
42 }
43 
BOOST_AUTO_TEST_CASE(test_condition_notify_all_wakes_from_wait)44 BOOST_AUTO_TEST_CASE(test_condition_notify_all_wakes_from_wait)
45 {
46     timed_test(&do_test_condition_notify_all_wakes_from_wait, timeout_seconds);
47 }
48 
do_test_condition_notify_all_wakes_from_wait_with_predicate()49 void do_test_condition_notify_all_wakes_from_wait_with_predicate()
50 {
51     wait_for_flag data;
52 
53     boost::thread_group group;
54 
55     try
56     {
57         for(unsigned i=0;i<number_of_test_threads;++i)
58         {
59             group.create_thread(bind(&wait_for_flag::wait_with_predicate, data));
60         }
61 
62         {
63             boost::sync::unique_lock<boost::sync::mutex> lock(data.mutex);
64             data.flag=true;
65             data.cond_var.notify_all();
66         }
67 
68         group.join_all();
69         BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
70     }
71     catch(...)
72     {
73         group.join_all();
74         throw;
75     }
76 }
77 
BOOST_AUTO_TEST_CASE(test_condition_notify_all_wakes_from_wait_with_predicate)78 BOOST_AUTO_TEST_CASE(test_condition_notify_all_wakes_from_wait_with_predicate)
79 {
80     timed_test(&do_test_condition_notify_all_wakes_from_wait_with_predicate, timeout_seconds);
81 }
82 
do_test_condition_notify_all_wakes_from_timed_wait()83 void do_test_condition_notify_all_wakes_from_timed_wait()
84 {
85     wait_for_flag data;
86 
87     boost::thread_group group;
88 
89     try
90     {
91         for(unsigned i=0;i<number_of_test_threads;++i)
92         {
93             group.create_thread(bind(&wait_for_flag::timed_wait_without_predicate, data));
94         }
95 
96         {
97             boost::sync::unique_lock<boost::sync::mutex> lock(data.mutex);
98             data.flag=true;
99             data.cond_var.notify_all();
100         }
101 
102         group.join_all();
103         BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
104     }
105     catch(...)
106     {
107         group.join_all();
108         throw;
109     }
110 }
111 
BOOST_AUTO_TEST_CASE(test_condition_notify_all_wakes_from_timed_wait)112 BOOST_AUTO_TEST_CASE(test_condition_notify_all_wakes_from_timed_wait)
113 {
114     timed_test(&do_test_condition_notify_all_wakes_from_timed_wait, timeout_seconds);
115 }
116 
do_test_condition_notify_all_wakes_from_timed_wait_with_predicate()117 void do_test_condition_notify_all_wakes_from_timed_wait_with_predicate()
118 {
119     wait_for_flag data;
120 
121     boost::thread_group group;
122 
123     try
124     {
125         for(unsigned i=0;i<number_of_test_threads;++i)
126         {
127             group.create_thread(bind(&wait_for_flag::timed_wait_with_predicate, data));
128         }
129 
130         {
131             boost::sync::unique_lock<boost::sync::mutex> lock(data.mutex);
132             data.flag=true;
133             data.cond_var.notify_all();
134         }
135 
136         group.join_all();
137         BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
138     }
139     catch(...)
140     {
141         group.join_all();
142         throw;
143     }
144 }
145 
BOOST_AUTO_TEST_CASE(test_condition_notify_all_wakes_from_timed_wait_with_predicate)146 BOOST_AUTO_TEST_CASE(test_condition_notify_all_wakes_from_timed_wait_with_predicate)
147 {
148     timed_test(&do_test_condition_notify_all_wakes_from_timed_wait_with_predicate, timeout_seconds);
149 }
150 
do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate()151 void do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate()
152 {
153     wait_for_flag data;
154 
155     boost::thread_group group;
156 
157     try
158     {
159         for(unsigned i=0;i<number_of_test_threads;++i)
160         {
161             group.create_thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data));
162         }
163 
164         {
165             boost::sync::unique_lock<boost::sync::mutex> lock(data.mutex);
166             data.flag=true;
167             data.cond_var.notify_all();
168         }
169 
170         group.join_all();
171         BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
172     }
173     catch(...)
174     {
175         group.join_all();
176         throw;
177     }
178 }
179 
BOOST_AUTO_TEST_CASE(test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate)180 BOOST_AUTO_TEST_CASE(test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate)
181 {
182     timed_test(&do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate, timeout_seconds);
183 }
184 
185 namespace {
186 
187 boost::sync::mutex multiple_wake_mutex;
188 boost::sync::condition_variable multiple_wake_cond;
189 unsigned multiple_wake_count = 0;
190 
wait_for_condvar_and_increase_count()191 void wait_for_condvar_and_increase_count()
192 {
193     boost::sync::unique_lock<boost::sync::mutex> lk(multiple_wake_mutex);
194     multiple_wake_cond.wait(lk);
195     ++multiple_wake_count;
196 }
197 
198 } // namespace
199 
do_test_notify_all_following_notify_one_wakes_all_threads()200 void do_test_notify_all_following_notify_one_wakes_all_threads()
201 {
202     boost::thread thread1(wait_for_condvar_and_increase_count);
203     boost::thread thread2(wait_for_condvar_and_increase_count);
204 
205     boost::this_thread::sleep(boost::posix_time::milliseconds(200));
206     multiple_wake_cond.notify_one();
207 
208     boost::thread thread3(wait_for_condvar_and_increase_count);
209 
210     boost::this_thread::sleep(boost::posix_time::milliseconds(200));
211     multiple_wake_cond.notify_one();
212     multiple_wake_cond.notify_all();
213     boost::this_thread::sleep(boost::posix_time::milliseconds(200));
214 
215     {
216         boost::sync::unique_lock<boost::sync::mutex> lk(multiple_wake_mutex);
217         BOOST_CHECK(multiple_wake_count==3);
218     }
219 
220     thread1.join();
221     thread2.join();
222     thread3.join();
223 }
224 
BOOST_AUTO_TEST_CASE(test_notify_all_following_notify_one_wakes_all_threads)225 BOOST_AUTO_TEST_CASE(test_notify_all_following_notify_one_wakes_all_threads)
226 {
227     timed_test(&do_test_notify_all_following_notify_one_wakes_all_threads, timeout_seconds);
228 }
229