]>
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 | */ | |
b32b8144 | 37 | template <class CallableThread = join_if_joinable, class Thread=::boost::thread> |
7c673cae FG |
38 | class strict_scoped_thread |
39 | { | |
b32b8144 | 40 | Thread t_; |
7c673cae FG |
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) | |
b32b8144 | 50 | template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type> |
7c673cae FG |
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, | |
b32b8144 | 56 | typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type=0) : |
7c673cae FG |
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 | */ | |
b32b8144 | 76 | explicit strict_scoped_thread(BOOST_THREAD_RV_REF(Thread) t) BOOST_NOEXCEPT : |
7c673cae FG |
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 | */ | |
b32b8144 | 114 | template <class CallableThread = join_if_joinable, class Thread=::boost::thread> |
7c673cae FG |
115 | class scoped_thread |
116 | { | |
b32b8144 | 117 | Thread t_; |
7c673cae FG |
118 | struct dummy; |
119 | public: | |
120 | ||
b32b8144 FG |
121 | typedef typename Thread::id id; |
122 | typedef typename Thread::native_handle_type native_handle_type; | |
7c673cae FG |
123 | |
124 | BOOST_THREAD_MOVABLE_ONLY( scoped_thread) /// Movable only | |
125 | ||
126 | /** | |
127 | * Default Constructor. | |
128 | * | |
129 | * Effects: wraps a not-a-thread. | |
130 | */ | |
131 | scoped_thread() BOOST_NOEXCEPT: | |
132 | t_() | |
133 | { | |
134 | } | |
135 | ||
136 | /** | |
137 | * | |
138 | */ | |
139 | ||
140 | #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) | |
b32b8144 | 141 | template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type> |
7c673cae FG |
142 | explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) : |
143 | t_(boost::forward<F>(f), boost::forward<Args>(args)...) {} | |
144 | #else | |
145 | template <class F> | |
146 | explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f, | |
b32b8144 | 147 | typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type=0) : |
7c673cae FG |
148 | t_(boost::forward<F>(f)) {} |
149 | template <class F, class A1> | |
150 | scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) : | |
151 | t_(boost::forward<F>(f), boost::forward<A1>(a1)) {} | |
152 | template <class F, class A1, class A2> | |
153 | scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2) : | |
154 | t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2)) {} | |
155 | template <class F, class A1, class A2, class A3> | |
156 | 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) : | |
157 | t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)) {} | |
158 | ||
159 | #endif | |
160 | /** | |
161 | * Constructor from the thread to own. | |
162 | * | |
163 | * @param t: the thread to own. | |
164 | * | |
165 | * Effects: move the thread to own @c t. | |
166 | */ | |
b32b8144 | 167 | explicit scoped_thread(BOOST_THREAD_RV_REF(Thread) t) BOOST_NOEXCEPT : |
7c673cae FG |
168 | t_(boost::move(t)) |
169 | { | |
170 | } | |
171 | ||
b32b8144 | 172 | // explicit operator Thread() |
7c673cae FG |
173 | // { |
174 | // return boost::move(t_); | |
175 | // } | |
176 | ||
177 | /** | |
178 | * Move constructor. | |
179 | */ | |
180 | scoped_thread(BOOST_RV_REF(scoped_thread) x) BOOST_NOEXCEPT : | |
181 | t_(boost::move(BOOST_THREAD_RV(x).t_)) | |
182 | {} | |
183 | ||
184 | /** | |
185 | * Destructor | |
186 | * | |
187 | * Effects: Call the CallableThread functor before destroying the owned thread. | |
188 | */ | |
189 | ~scoped_thread() | |
190 | { | |
191 | CallableThread on_destructor; | |
192 | ||
193 | on_destructor(t_); | |
194 | } | |
195 | ||
196 | /** | |
197 | * Move assignment. | |
198 | */ | |
199 | scoped_thread& operator=(BOOST_RV_REF(scoped_thread) x) | |
200 | { | |
201 | CallableThread on_destructor; | |
202 | ||
203 | on_destructor(t_); | |
204 | t_ = boost::move(BOOST_THREAD_RV(x).t_); | |
205 | return *this; | |
206 | } | |
207 | ||
208 | /** | |
209 | * | |
210 | */ | |
211 | void swap(scoped_thread& x) BOOST_NOEXCEPT | |
212 | { | |
213 | t_.swap(x.t_); | |
214 | } | |
215 | ||
216 | // forwarded thread functions | |
b32b8144 | 217 | inline id get_id() const BOOST_NOEXCEPT |
7c673cae FG |
218 | { |
219 | return t_.get_id(); | |
220 | } | |
221 | ||
222 | void detach() | |
223 | { | |
224 | t_.detach(); | |
225 | } | |
226 | ||
227 | void join() | |
228 | { | |
229 | t_.join(); | |
230 | } | |
231 | ||
232 | #ifdef BOOST_THREAD_USES_CHRONO | |
233 | template <class Rep, class Period> | |
234 | bool try_join_for(const chrono::duration<Rep, Period>& rel_time) | |
235 | { | |
236 | return t_.try_join_for(rel_time); | |
237 | } | |
238 | ||
239 | template <class Clock, class Duration> | |
240 | bool try_join_until(const chrono::time_point<Clock, Duration>& abs_time) | |
241 | { | |
242 | return t_.try_join_until(abs_time); | |
243 | } | |
244 | #endif | |
245 | ||
b32b8144 | 246 | native_handle_type native_handle()BOOST_NOEXCEPT |
7c673cae FG |
247 | { |
248 | return t_.native_handle(); | |
249 | } | |
250 | ||
251 | bool joinable() const BOOST_NOEXCEPT | |
252 | { | |
253 | return t_.joinable(); | |
254 | } | |
255 | ||
256 | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | |
257 | void interrupt() | |
258 | { | |
259 | t_.interrupt(); | |
260 | } | |
261 | ||
262 | bool interruption_requested() const BOOST_NOEXCEPT | |
263 | { | |
264 | return t_.interruption_requested(); | |
265 | } | |
266 | #endif | |
267 | ||
268 | static unsigned hardware_concurrency() BOOST_NOEXCEPT | |
269 | { | |
b32b8144 | 270 | return Thread::hardware_concurrency(); |
7c673cae FG |
271 | } |
272 | ||
273 | #ifdef BOOST_THREAD_PROVIDES_PHYSICAL_CONCURRENCY | |
274 | static unsigned physical_concurrency() BOOST_NOEXCEPT | |
275 | { | |
b32b8144 | 276 | return Thread::physical_concurrency(); |
7c673cae FG |
277 | } |
278 | #endif | |
279 | }; | |
280 | ||
281 | /** | |
282 | * Effects: swaps the contents of two scoped threads. | |
283 | */ | |
b32b8144 FG |
284 | template <class Destroyer, class Thread > |
285 | void swap(scoped_thread<Destroyer, Thread>& lhs, scoped_thread<Destroyer, Thread>& rhs) | |
7c673cae FG |
286 | BOOST_NOEXCEPT { |
287 | return lhs.swap(rhs); | |
288 | } | |
289 | ||
b32b8144 | 290 | typedef scoped_thread<> joining_thread; |
7c673cae FG |
291 | } |
292 | #include <boost/config/abi_suffix.hpp> | |
293 | ||
294 | #endif |