1 | // Copyright (C) 2001-2003 |
2 | // William E. Kempf |
3 | // Copyright (C) 2008 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 | |
11 | #include <boost/thread/detail/config.hpp> |
12 | |
13 | #include <boost/thread/thread_only.hpp> |
14 | #include <boost/thread/xtime.hpp> |
15 | #include <boost/bind/bind.hpp> |
16 | #include <boost/ref.hpp> |
17 | #include <boost/utility.hpp> |
18 | |
19 | #define BOOST_TEST_MODULE Boost.Threads: thread test suite |
20 | |
21 | #include <boost/test/unit_test.hpp> |
22 | |
23 | #define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only |
24 | #include "./util.inl" |
25 | |
26 | int test_value; |
27 | |
28 | void simple_thread() |
29 | { |
30 | test_value = 999; |
31 | } |
32 | |
33 | void comparison_thread(boost::thread::id parent) |
34 | { |
35 | boost::thread::id const my_id=boost::this_thread::get_id(); |
36 | |
37 | BOOST_CHECK(my_id != parent); |
38 | boost::thread::id const my_id2=boost::this_thread::get_id(); |
39 | BOOST_CHECK(my_id == my_id2); |
40 | |
41 | boost::thread::id const no_thread_id=boost::thread::id(); |
42 | BOOST_CHECK(my_id != no_thread_id); |
43 | } |
44 | |
45 | BOOST_AUTO_TEST_CASE(test_sleep) |
46 | { |
47 | boost::xtime xt = delay(secs: 3); |
48 | boost::thread::sleep(xt); |
49 | |
50 | // Ensure it's in a range instead of checking actual equality due to time |
51 | // lapse |
52 | BOOST_CHECK(boost::threads::test::in_range(xt, 2)); |
53 | } |
54 | |
55 | void do_test_creation() |
56 | { |
57 | test_value = 0; |
58 | boost::thread thrd(&simple_thread); |
59 | thrd.join(); |
60 | BOOST_CHECK_EQUAL(test_value, 999); |
61 | } |
62 | |
63 | BOOST_AUTO_TEST_CASE(test_creation) |
64 | { |
65 | timed_test(func: &do_test_creation, secs: 1); |
66 | } |
67 | |
68 | void do_test_id_comparison() |
69 | { |
70 | boost::thread::id const self=boost::this_thread::get_id(); |
71 | boost::thread thrd(boost::bind(f: &comparison_thread, a1: self)); |
72 | thrd.join(); |
73 | } |
74 | |
75 | BOOST_AUTO_TEST_CASE(test_id_comparison) |
76 | { |
77 | timed_test(func: &do_test_id_comparison, secs: 1); |
78 | } |
79 | |
80 | void interruption_point_thread(boost::mutex* m,bool* failed) |
81 | { |
82 | boost::unique_lock<boost::mutex> lk(*m); |
83 | boost::this_thread::interruption_point(); |
84 | *failed=true; |
85 | } |
86 | |
87 | void do_test_thread_interrupts_at_interruption_point() |
88 | { |
89 | boost::mutex m; |
90 | bool failed=false; |
91 | boost::unique_lock<boost::mutex> lk(m); |
92 | boost::thread thrd(boost::bind(f: &interruption_point_thread,a1: &m,a2: &failed)); |
93 | thrd.interrupt(); |
94 | lk.unlock(); |
95 | thrd.join(); |
96 | BOOST_CHECK(!failed); |
97 | } |
98 | |
99 | BOOST_AUTO_TEST_CASE(test_thread_interrupts_at_interruption_point) |
100 | { |
101 | timed_test(func: &do_test_thread_interrupts_at_interruption_point, secs: 1); |
102 | } |
103 | |
104 | void disabled_interruption_point_thread(boost::mutex* m,bool* failed) |
105 | { |
106 | boost::unique_lock<boost::mutex> lk(*m); |
107 | boost::this_thread::disable_interruption dc; |
108 | boost::this_thread::interruption_point(); |
109 | *failed=false; |
110 | } |
111 | |
112 | void do_test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point() |
113 | { |
114 | boost::mutex m; |
115 | bool failed=true; |
116 | boost::unique_lock<boost::mutex> lk(m); |
117 | boost::thread thrd(boost::bind(f: &disabled_interruption_point_thread,a1: &m,a2: &failed)); |
118 | thrd.interrupt(); |
119 | lk.unlock(); |
120 | thrd.join(); |
121 | BOOST_CHECK(!failed); |
122 | } |
123 | |
124 | BOOST_AUTO_TEST_CASE(test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point) |
125 | { |
126 | timed_test(func: &do_test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point, secs: 1); |
127 | } |
128 | |
129 | struct non_copyable_functor: |
130 | boost::noncopyable |
131 | { |
132 | unsigned value; |
133 | |
134 | non_copyable_functor(): boost::noncopyable(), |
135 | value(0) |
136 | {} |
137 | |
138 | void operator()() |
139 | { |
140 | value=999; |
141 | } |
142 | }; |
143 | |
144 | void do_test_creation_through_reference_wrapper() |
145 | { |
146 | non_copyable_functor f; |
147 | |
148 | boost::thread thrd(boost::ref(t&: f)); |
149 | thrd.join(); |
150 | BOOST_CHECK_EQUAL(f.value, 999u); |
151 | } |
152 | |
153 | BOOST_AUTO_TEST_CASE(test_creation_through_reference_wrapper) |
154 | { |
155 | timed_test(func: &do_test_creation_through_reference_wrapper, secs: 1); |
156 | } |
157 | |
158 | struct long_running_thread |
159 | { |
160 | boost::condition_variable cond; |
161 | boost::mutex mut; |
162 | bool done; |
163 | |
164 | long_running_thread(): |
165 | done(false) |
166 | {} |
167 | |
168 | void operator()() |
169 | { |
170 | boost::unique_lock<boost::mutex> lk(mut); |
171 | while(!done) |
172 | { |
173 | cond.wait(m&: lk); |
174 | } |
175 | } |
176 | }; |
177 | |
178 | void do_test_timed_join() |
179 | { |
180 | long_running_thread f; |
181 | boost::thread thrd(boost::ref(t&: f)); |
182 | BOOST_CHECK(thrd.joinable()); |
183 | boost::system_time xt=delay(secs: 3); |
184 | bool const joined=thrd.timed_join(abs_time: xt); |
185 | BOOST_CHECK(boost::threads::test::in_range(boost::get_xtime(xt), 2)); |
186 | BOOST_CHECK(!joined); |
187 | BOOST_CHECK(thrd.joinable()); |
188 | { |
189 | boost::unique_lock<boost::mutex> lk(f.mut); |
190 | f.done=true; |
191 | f.cond.notify_one(); |
192 | } |
193 | |
194 | xt=delay(secs: 3); |
195 | bool const joined2=thrd.timed_join(abs_time: xt); |
196 | boost::system_time const now=boost::get_system_time(); |
197 | BOOST_CHECK(xt>now); |
198 | BOOST_CHECK(joined2); |
199 | BOOST_CHECK(!thrd.joinable()); |
200 | } |
201 | |
202 | BOOST_AUTO_TEST_CASE(test_timed_join) |
203 | { |
204 | timed_test(func: &do_test_timed_join, secs: 10); |
205 | } |
206 | |
207 | BOOST_AUTO_TEST_CASE(test_swap) |
208 | { |
209 | boost::thread t(&simple_thread); |
210 | boost::thread t2(&simple_thread); |
211 | boost::thread::id id1=t.get_id(); |
212 | boost::thread::id id2=t2.get_id(); |
213 | |
214 | t.swap(x&: t2); |
215 | BOOST_CHECK(t.get_id()==id2); |
216 | BOOST_CHECK(t2.get_id()==id1); |
217 | |
218 | swap(lhs&: t,rhs&: t2); |
219 | BOOST_CHECK(t.get_id()==id1); |
220 | BOOST_CHECK(t2.get_id()==id2); |
221 | } |
222 | |
223 | |