1 | // Copyright (C) 2001-2003 |
2 | // William E. Kempf |
3 | // Copyright (C) 2007 Anthony Williams |
4 | // |
5 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
6 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
7 | |
8 | #define BOOST_THREAD_VERSION 2 |
9 | #define BOOST_THREAD_PROVIDES_INTERRUPTIONS |
10 | #define BOOST_TEST_MODULE Boost.Threads: condition test suite |
11 | #include <boost/thread/detail/config.hpp> |
12 | |
13 | #include <boost/thread/condition.hpp> |
14 | #include <boost/thread/thread_only.hpp> |
15 | #include <boost/thread/xtime.hpp> |
16 | |
17 | #include <boost/config.hpp> |
18 | #include <boost/test/unit_test.hpp> |
19 | |
20 | #include "./util.inl" |
21 | |
22 | struct condition_test_data |
23 | { |
24 | condition_test_data() : notified(0), awoken(0) { } |
25 | |
26 | boost::mutex mutex; |
27 | boost::condition_variable condition; |
28 | int notified; |
29 | int awoken; |
30 | }; |
31 | |
32 | void condition_test_thread(condition_test_data* data) |
33 | { |
34 | boost::unique_lock<boost::mutex> lock(data->mutex); |
35 | BOOST_CHECK(lock ? true : false); |
36 | while (!(data->notified > 0)) |
37 | data->condition.wait(m&: lock); |
38 | BOOST_CHECK(lock ? true : false); |
39 | data->awoken++; |
40 | } |
41 | |
42 | struct cond_predicate |
43 | { |
44 | cond_predicate(int& var, int val) : _var(var), _val(val) { } |
45 | #if !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) |
46 | cond_predicate(cond_predicate const&) = default; |
47 | #endif |
48 | |
49 | bool operator()() { return _var == _val; } |
50 | |
51 | int& _var; |
52 | int _val; |
53 | |
54 | private: |
55 | void operator=(cond_predicate&); |
56 | }; |
57 | |
58 | void condition_test_waits(condition_test_data* data) |
59 | { |
60 | boost::unique_lock<boost::mutex> lock(data->mutex); |
61 | BOOST_CHECK(lock ? true : false); |
62 | |
63 | // Test wait. |
64 | while (data->notified != 1) |
65 | data->condition.wait(m&: lock); |
66 | BOOST_CHECK(lock ? true : false); |
67 | BOOST_CHECK_EQUAL(data->notified, 1); |
68 | data->awoken++; |
69 | data->condition.notify_one(); |
70 | |
71 | // Test predicate wait. |
72 | data->condition.wait(m&: lock, pred: cond_predicate(data->notified, 2)); |
73 | BOOST_CHECK(lock ? true : false); |
74 | BOOST_CHECK_EQUAL(data->notified, 2); |
75 | data->awoken++; |
76 | data->condition.notify_one(); |
77 | |
78 | // Test timed_wait. |
79 | boost::xtime xt = delay(secs: 10); |
80 | while (data->notified != 3) |
81 | data->condition.timed_wait(m&: lock, abs_time: xt); |
82 | BOOST_CHECK(lock ? true : false); |
83 | BOOST_CHECK_EQUAL(data->notified, 3); |
84 | data->awoken++; |
85 | data->condition.notify_one(); |
86 | |
87 | // Test predicate timed_wait. |
88 | xt = delay(secs: 10); |
89 | cond_predicate pred(data->notified, 4); |
90 | BOOST_CHECK(data->condition.timed_wait(lock, xt, pred)); |
91 | BOOST_CHECK(lock ? true : false); |
92 | BOOST_CHECK(pred()); |
93 | BOOST_CHECK_EQUAL(data->notified, 4); |
94 | data->awoken++; |
95 | data->condition.notify_one(); |
96 | |
97 | // Test predicate timed_wait with relative timeout |
98 | cond_predicate pred_rel(data->notified, 5); |
99 | BOOST_CHECK(data->condition.timed_wait(lock, boost::posix_time::seconds(10), pred_rel)); |
100 | BOOST_CHECK(lock ? true : false); |
101 | BOOST_CHECK(pred_rel()); |
102 | BOOST_CHECK_EQUAL(data->notified, 5); |
103 | data->awoken++; |
104 | data->condition.notify_one(); |
105 | } |
106 | |
107 | void do_test_condition_waits() |
108 | { |
109 | condition_test_data data; |
110 | |
111 | boost::thread thread(bind(func: &condition_test_waits, param: &data)); |
112 | |
113 | { |
114 | boost::unique_lock<boost::mutex> lock(data.mutex); |
115 | BOOST_CHECK(lock ? true : false); |
116 | |
117 | boost::thread::sleep(xt: delay(secs: 1)); |
118 | data.notified++; |
119 | data.condition.notify_one(); |
120 | while (data.awoken != 1) |
121 | data.condition.wait(m&: lock); |
122 | BOOST_CHECK(lock ? true : false); |
123 | BOOST_CHECK_EQUAL(data.awoken, 1); |
124 | |
125 | boost::thread::sleep(xt: delay(secs: 1)); |
126 | data.notified++; |
127 | data.condition.notify_one(); |
128 | while (data.awoken != 2) |
129 | data.condition.wait(m&: lock); |
130 | BOOST_CHECK(lock ? true : false); |
131 | BOOST_CHECK_EQUAL(data.awoken, 2); |
132 | |
133 | boost::thread::sleep(xt: delay(secs: 1)); |
134 | data.notified++; |
135 | data.condition.notify_one(); |
136 | while (data.awoken != 3) |
137 | data.condition.wait(m&: lock); |
138 | BOOST_CHECK(lock ? true : false); |
139 | BOOST_CHECK_EQUAL(data.awoken, 3); |
140 | |
141 | boost::thread::sleep(xt: delay(secs: 1)); |
142 | data.notified++; |
143 | data.condition.notify_one(); |
144 | while (data.awoken != 4) |
145 | data.condition.wait(m&: lock); |
146 | BOOST_CHECK(lock ? true : false); |
147 | BOOST_CHECK_EQUAL(data.awoken, 4); |
148 | |
149 | |
150 | boost::thread::sleep(xt: delay(secs: 1)); |
151 | data.notified++; |
152 | data.condition.notify_one(); |
153 | while (data.awoken != 5) |
154 | data.condition.wait(m&: lock); |
155 | BOOST_CHECK(lock ? true : false); |
156 | BOOST_CHECK_EQUAL(data.awoken, 5); |
157 | } |
158 | |
159 | thread.join(); |
160 | BOOST_CHECK_EQUAL(data.awoken, 5); |
161 | } |
162 | |
163 | BOOST_AUTO_TEST_CASE(test_condition_waits) |
164 | { |
165 | // We should have already tested notify_one here, so |
166 | // a timed test with the default execution_monitor::use_condition |
167 | // should be OK, and gives the fastest performance |
168 | timed_test(func: &do_test_condition_waits, secs: 12); |
169 | } |
170 | |
171 | void do_test_condition_wait_is_a_interruption_point() |
172 | { |
173 | condition_test_data data; |
174 | |
175 | boost::thread thread(bind(func: &condition_test_thread, param: &data)); |
176 | |
177 | thread.interrupt(); |
178 | thread.join(); |
179 | BOOST_CHECK_EQUAL(data.awoken,0); |
180 | } |
181 | |
182 | |
183 | BOOST_AUTO_TEST_CASE(test_condition_wait_is_a_interruption_point) |
184 | { |
185 | timed_test(func: &do_test_condition_wait_is_a_interruption_point, secs: 1); |
186 | } |
187 | |
188 | |