]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Distributed under the Boost Software License, Version 1.0. (See |
2 | // accompanying file LICENSE_1_0.txt or copy at | |
3 | // http://www.boost.org/LICENSE_1_0.txt) | |
4 | // (C) Copyright 2009-2012 Anthony Williams | |
5 | // (C) Copyright 2012 Vicente J. Botet Escriba | |
6 | ||
7 | // Based on the Anthony's idea of scoped_thread in CCiA | |
8 | ||
9 | #ifndef BOOST_THREAD_SCOPED_THREAD_HPP | |
10 | #define BOOST_THREAD_SCOPED_THREAD_HPP | |
11 | ||
12 | #include <boost/thread/detail/config.hpp> | |
13 | #include <boost/thread/detail/delete.hpp> | |
14 | #include <boost/thread/detail/move.hpp> | |
15 | #include <boost/thread/thread_functors.hpp> | |
16 | #include <boost/thread/thread_only.hpp> | |
17 | ||
18 | #include <boost/config/abi_prefix.hpp> | |
19 | ||
20 | namespace boost | |
21 | { | |
22 | ||
23 | /** | |
24 | * RAI @c thread wrapper adding a specific destroyer allowing to master what can be done at destruction time. | |
25 | * | |
26 | * CallableThread: A callable void(thread&) . | |
27 | * The default is a join_if_joinable. | |
28 | * | |
29 | * thread std/boost::thread destructor terminates the program if the thread is not joinable. | |
30 | * Having a wrapper that can join the thread before destroying it seems a natural need. | |
31 | * | |
32 | * Example: | |
33 | * | |
34 | * boost::strict_scoped_thread<> t((boost::thread(F))); | |
35 | * | |
36 | */ | |
37 | template <class CallableThread = join_if_joinable> | |
38 | class strict_scoped_thread | |
39 | { | |
40 | thread t_; | |
41 | struct dummy; | |
42 | public: | |
43 | ||
44 | BOOST_THREAD_NO_COPYABLE( strict_scoped_thread) /// non copyable | |
45 | ||
46 | /* | |
47 | * | |
48 | */ | |
49 | #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) | |
50 | template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type> | |
51 | explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) : | |
52 | t_(boost::forward<F>(f), boost::forward<Args>(args)...) {} | |
53 | #else | |
54 | template <class F> | |
55 | explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, | |
56 | typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type=0) : | |
57 | t_(boost::forward<F>(f)) {} | |
58 | template <class F, class A1> | |
59 | strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) : | |
60 | t_(boost::forward<F>(f), boost::forward<A1>(a1)) {} | |
61 | template <class F, class A1, class A2> | |
62 | strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2) : | |
63 | t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2)) {} | |
64 | template <class F, class A1, class A2, class A3> | |
65 | strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2, BOOST_THREAD_FWD_REF(A3) a3) : | |
66 | t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)) {} | |
67 | #endif | |
68 | ||
69 | /** | |
70 | * Constructor from the thread to own. | |
71 | * | |
72 | * @param t: the thread to own. | |
73 | * | |
74 | * Effects: move the thread to own @c t. | |
75 | */ | |
76 | explicit strict_scoped_thread(BOOST_THREAD_RV_REF(thread) t) BOOST_NOEXCEPT : | |
77 | t_(boost::move(t)) | |
78 | { | |
79 | } | |
80 | ||
81 | /** | |
82 | * Destructor | |
83 | * Effects: Call the CallableThread functor before destroying the owned thread. | |
84 | * Remark: The CallableThread should not throw when joining the thread as the scoped variable is on a scope outside the thread function. | |
85 | */ | |
86 | ~strict_scoped_thread() | |
87 | { | |
88 | CallableThread on_destructor; | |
89 | ||
90 | on_destructor(t_); | |
91 | } | |
92 | ||
93 | }; | |
94 | ||
95 | /** | |
96 | * RAI @c thread wrapper adding a specific destroyer allowing to master what can be done at destruction time. | |
97 | * | |
98 | * CallableThread: A callable void(thread&) . | |
99 | * The default is join_if_joinable. | |
100 | * | |
101 | * thread std::thread destructor terminates the program if the thread is not joinable. | |
102 | * Having a wrapper that can join the thread before destroying it seems a natural need. | |
103 | * | |
104 | * Remark: @c scoped_thread is not a @c thread as @c thread is not designed to be derived from as a polymorphic type. | |
105 | * Anyway @c scoped_thread can be used in most of the contexts a @c thread could be used as it has the | |
106 | * same non-deprecated interface with the exception of the construction. | |
107 | * | |
108 | * Example: | |
109 | * | |
110 | * boost::scoped_thread<> t((boost::thread(F))); | |
111 | * t.interrupt(); | |
112 | * | |
113 | */ | |
114 | template <class CallableThread = join_if_joinable> | |
115 | class scoped_thread | |
116 | { | |
117 | thread t_; | |
118 | struct dummy; | |
119 | public: | |
120 | ||
121 | typedef thread::id id; | |
122 | ||
123 | BOOST_THREAD_MOVABLE_ONLY( scoped_thread) /// Movable only | |
124 | ||
125 | /** | |
126 | * Default Constructor. | |
127 | * | |
128 | * Effects: wraps a not-a-thread. | |
129 | */ | |
130 | scoped_thread() BOOST_NOEXCEPT: | |
131 | t_() | |
132 | { | |
133 | } | |
134 | ||
135 | /** | |
136 | * | |
137 | */ | |
138 | ||
139 | #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) | |
140 | template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type> | |
141 | explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) : | |
142 | t_(boost::forward<F>(f), boost::forward<Args>(args)...) {} | |
143 | #else | |
144 | template <class F> | |
145 | explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f, | |
146 | typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type=0) : | |
147 | t_(boost::forward<F>(f)) {} | |
148 | template <class F, class A1> | |
149 | scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) : | |
150 | t_(boost::forward<F>(f), boost::forward<A1>(a1)) {} | |
151 | template <class F, class A1, class A2> | |
152 | scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2) : | |
153 | t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2)) {} | |
154 | template <class F, class A1, class A2, class A3> | |
155 | scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2, BOOST_THREAD_FWD_REF(A3) a3) : | |
156 | t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)) {} | |
157 | ||
158 | #endif | |
159 | /** | |
160 | * Constructor from the thread to own. | |
161 | * | |
162 | * @param t: the thread to own. | |
163 | * | |
164 | * Effects: move the thread to own @c t. | |
165 | */ | |
166 | explicit scoped_thread(BOOST_THREAD_RV_REF(thread) t) BOOST_NOEXCEPT : | |
167 | t_(boost::move(t)) | |
168 | { | |
169 | } | |
170 | ||
171 | // explicit operator thread() | |
172 | // { | |
173 | // return boost::move(t_); | |
174 | // } | |
175 | ||
176 | /** | |
177 | * Move constructor. | |
178 | */ | |
179 | scoped_thread(BOOST_RV_REF(scoped_thread) x) BOOST_NOEXCEPT : | |
180 | t_(boost::move(BOOST_THREAD_RV(x).t_)) | |
181 | {} | |
182 | ||
183 | /** | |
184 | * Destructor | |
185 | * | |
186 | * Effects: Call the CallableThread functor before destroying the owned thread. | |
187 | */ | |
188 | ~scoped_thread() | |
189 | { | |
190 | CallableThread on_destructor; | |
191 | ||
192 | on_destructor(t_); | |
193 | } | |
194 | ||
195 | /** | |
196 | * Move assignment. | |
197 | */ | |
198 | scoped_thread& operator=(BOOST_RV_REF(scoped_thread) x) | |
199 | { | |
200 | CallableThread on_destructor; | |
201 | ||
202 | on_destructor(t_); | |
203 | t_ = boost::move(BOOST_THREAD_RV(x).t_); | |
204 | return *this; | |
205 | } | |
206 | ||
207 | /** | |
208 | * | |
209 | */ | |
210 | void swap(scoped_thread& x) BOOST_NOEXCEPT | |
211 | { | |
212 | t_.swap(x.t_); | |
213 | } | |
214 | ||
215 | // forwarded thread functions | |
216 | inline thread::id get_id() const BOOST_NOEXCEPT | |
217 | { | |
218 | return t_.get_id(); | |
219 | } | |
220 | ||
221 | void detach() | |
222 | { | |
223 | t_.detach(); | |
224 | } | |
225 | ||
226 | void join() | |
227 | { | |
228 | t_.join(); | |
229 | } | |
230 | ||
231 | #ifdef BOOST_THREAD_USES_CHRONO | |
232 | template <class Rep, class Period> | |
233 | bool try_join_for(const chrono::duration<Rep, Period>& rel_time) | |
234 | { | |
235 | return t_.try_join_for(rel_time); | |
236 | } | |
237 | ||
238 | template <class Clock, class Duration> | |
239 | bool try_join_until(const chrono::time_point<Clock, Duration>& abs_time) | |
240 | { | |
241 | return t_.try_join_until(abs_time); | |
242 | } | |
243 | #endif | |
244 | ||
245 | thread::native_handle_type native_handle()BOOST_NOEXCEPT | |
246 | { | |
247 | return t_.native_handle(); | |
248 | } | |
249 | ||
250 | bool joinable() const BOOST_NOEXCEPT | |
251 | { | |
252 | return t_.joinable(); | |
253 | } | |
254 | ||
255 | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | |
256 | void interrupt() | |
257 | { | |
258 | t_.interrupt(); | |
259 | } | |
260 | ||
261 | bool interruption_requested() const BOOST_NOEXCEPT | |
262 | { | |
263 | return t_.interruption_requested(); | |
264 | } | |
265 | #endif | |
266 | ||
267 | static unsigned hardware_concurrency() BOOST_NOEXCEPT | |
268 | { | |
269 | return thread::hardware_concurrency(); | |
270 | } | |
271 | ||
272 | #ifdef BOOST_THREAD_PROVIDES_PHYSICAL_CONCURRENCY | |
273 | static unsigned physical_concurrency() BOOST_NOEXCEPT | |
274 | { | |
275 | return thread::physical_concurrency(); | |
276 | } | |
277 | #endif | |
278 | }; | |
279 | ||
280 | /** | |
281 | * Effects: swaps the contents of two scoped threads. | |
282 | */ | |
283 | template <class Destroyer> | |
284 | void swap(scoped_thread<Destroyer>& lhs, scoped_thread<Destroyer>& rhs) | |
285 | BOOST_NOEXCEPT { | |
286 | return lhs.swap(rhs); | |
287 | } | |
288 | ||
289 | } | |
290 | #include <boost/config/abi_suffix.hpp> | |
291 | ||
292 | #endif |