]>
Commit | Line | Data |
---|---|---|
1 | #ifndef BOOST_THREAD_THREAD_COMMON_HPP | |
2 | #define BOOST_THREAD_THREAD_COMMON_HPP | |
3 | // Distributed under the Boost Software License, Version 1.0. (See | |
4 | // accompanying file LICENSE_1_0.txt or copy at | |
5 | // http://www.boost.org/LICENSE_1_0.txt) | |
6 | // (C) Copyright 2007-2010 Anthony Williams | |
7 | // (C) Copyright 2011-2012 Vicente J. Botet Escriba | |
8 | ||
9 | #include <boost/thread/detail/config.hpp> | |
10 | #include <boost/predef/platform.h> | |
11 | ||
12 | #include <boost/thread/exceptions.hpp> | |
13 | #ifndef BOOST_NO_IOSTREAM | |
14 | #include <ostream> | |
15 | #endif | |
16 | #include <boost/thread/detail/move.hpp> | |
17 | #include <boost/thread/mutex.hpp> | |
18 | #if defined BOOST_THREAD_USES_DATETIME | |
19 | #include <boost/thread/xtime.hpp> | |
20 | #endif | |
21 | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | |
22 | #include <boost/thread/interruption.hpp> | |
23 | #endif | |
24 | #include <boost/thread/detail/thread_heap_alloc.hpp> | |
25 | #include <boost/thread/detail/make_tuple_indices.hpp> | |
26 | #include <boost/thread/detail/invoke.hpp> | |
27 | #include <boost/thread/detail/is_convertible.hpp> | |
28 | #include <boost/assert.hpp> | |
29 | #include <list> | |
30 | #include <algorithm> | |
31 | #include <boost/core/ref.hpp> | |
32 | #include <boost/cstdint.hpp> | |
33 | #include <boost/bind/bind.hpp> | |
34 | #include <stdlib.h> | |
35 | #include <memory> | |
36 | #include <boost/core/enable_if.hpp> | |
37 | #include <boost/type_traits/remove_reference.hpp> | |
38 | #include <boost/io/ios_state.hpp> | |
39 | #include <boost/type_traits/is_same.hpp> | |
40 | #include <boost/type_traits/decay.hpp> | |
41 | #include <boost/functional/hash.hpp> | |
42 | #include <boost/thread/detail/platform_time.hpp> | |
43 | #ifdef BOOST_THREAD_USES_CHRONO | |
44 | #include <boost/chrono/system_clocks.hpp> | |
45 | #include <boost/chrono/ceil.hpp> | |
46 | #endif | |
47 | ||
48 | #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) | |
49 | #include <tuple> | |
50 | #endif | |
51 | #include <boost/config/abi_prefix.hpp> | |
52 | ||
53 | #ifdef BOOST_MSVC | |
54 | #pragma warning(push) | |
55 | #pragma warning(disable:4251) | |
56 | #endif | |
57 | ||
58 | namespace boost | |
59 | { | |
60 | ||
61 | namespace detail | |
62 | { | |
63 | ||
64 | #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) | |
65 | ||
66 | template<typename F, class ...ArgTypes> | |
67 | class thread_data: | |
68 | public detail::thread_data_base | |
69 | { | |
70 | public: | |
71 | BOOST_THREAD_NO_COPYABLE(thread_data) | |
72 | thread_data(BOOST_THREAD_RV_REF(F) f_, BOOST_THREAD_RV_REF(ArgTypes)... args_): | |
73 | fp(boost::forward<F>(f_), boost::forward<ArgTypes>(args_)...) | |
74 | {} | |
75 | template <std::size_t ...Indices> | |
76 | void run2(tuple_indices<Indices...>) | |
77 | { | |
78 | ||
79 | detail::invoke(std::move(std::get<0>(fp)), std::move(std::get<Indices>(fp))...); | |
80 | } | |
81 | void run() | |
82 | { | |
83 | typedef typename make_tuple_indices<std::tuple_size<std::tuple<F, ArgTypes...> >::value, 1>::type index_type; | |
84 | ||
85 | run2(index_type()); | |
86 | } | |
87 | ||
88 | private: | |
89 | std::tuple<typename decay<F>::type, typename decay<ArgTypes>::type...> fp; | |
90 | }; | |
91 | #else // defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) | |
92 | ||
93 | template<typename F> | |
94 | class thread_data: | |
95 | public detail::thread_data_base | |
96 | { | |
97 | public: | |
98 | BOOST_THREAD_NO_COPYABLE(thread_data) | |
99 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | |
100 | thread_data(BOOST_THREAD_RV_REF(F) f_): | |
101 | f(boost::forward<F>(f_)) | |
102 | {} | |
103 | // This overloading must be removed if we want the packaged_task's tests to pass. | |
104 | // thread_data(F& f_): | |
105 | // f(f_) | |
106 | // {} | |
107 | #else | |
108 | ||
109 | thread_data(BOOST_THREAD_RV_REF(F) f_): | |
110 | f(f_) | |
111 | {} | |
112 | thread_data(F f_): | |
113 | f(f_) | |
114 | {} | |
115 | #endif | |
116 | //thread_data() {} | |
117 | ||
118 | void run() | |
119 | { | |
120 | f(); | |
121 | } | |
122 | ||
123 | private: | |
124 | F f; | |
125 | }; | |
126 | ||
127 | template<typename F> | |
128 | class thread_data<boost::reference_wrapper<F> >: | |
129 | public detail::thread_data_base | |
130 | { | |
131 | private: | |
132 | F& f; | |
133 | public: | |
134 | BOOST_THREAD_NO_COPYABLE(thread_data) | |
135 | thread_data(boost::reference_wrapper<F> f_): | |
136 | f(f_) | |
137 | {} | |
138 | void run() | |
139 | { | |
140 | f(); | |
141 | } | |
142 | }; | |
143 | ||
144 | template<typename F> | |
145 | class thread_data<const boost::reference_wrapper<F> >: | |
146 | public detail::thread_data_base | |
147 | { | |
148 | private: | |
149 | F& f; | |
150 | public: | |
151 | BOOST_THREAD_NO_COPYABLE(thread_data) | |
152 | thread_data(const boost::reference_wrapper<F> f_): | |
153 | f(f_) | |
154 | {} | |
155 | void run() | |
156 | { | |
157 | f(); | |
158 | } | |
159 | }; | |
160 | #endif | |
161 | } | |
162 | ||
163 | class BOOST_THREAD_DECL thread | |
164 | { | |
165 | public: | |
166 | typedef thread_attributes attributes; | |
167 | ||
168 | BOOST_THREAD_MOVABLE_ONLY(thread) | |
169 | private: | |
170 | ||
171 | struct dummy; | |
172 | ||
173 | void release_handle(); | |
174 | ||
175 | detail::thread_data_ptr thread_info; | |
176 | ||
177 | private: | |
178 | bool start_thread_noexcept(); | |
179 | bool start_thread_noexcept(const attributes& attr); | |
180 | void start_thread() | |
181 | { | |
182 | if (!start_thread_noexcept()) | |
183 | { | |
184 | boost::throw_exception(thread_resource_error()); | |
185 | } | |
186 | } | |
187 | void start_thread(const attributes& attr) | |
188 | { | |
189 | if (!start_thread_noexcept(attr)) | |
190 | { | |
191 | boost::throw_exception(thread_resource_error()); | |
192 | } | |
193 | } | |
194 | ||
195 | explicit thread(detail::thread_data_ptr data); | |
196 | ||
197 | detail::thread_data_ptr get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const; | |
198 | ||
199 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | |
200 | #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) | |
201 | template<typename F, class ...ArgTypes> | |
202 | static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_RV_REF(ArgTypes)... args) | |
203 | { | |
204 | return detail::thread_data_ptr(detail::heap_new< | |
205 | detail::thread_data<typename boost::remove_reference<F>::type, ArgTypes...> | |
206 | >( | |
207 | boost::forward<F>(f), boost::forward<ArgTypes>(args)... | |
208 | ) | |
209 | ); | |
210 | } | |
211 | #else | |
212 | template<typename F> | |
213 | static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f) | |
214 | { | |
215 | return detail::thread_data_ptr(detail::heap_new<detail::thread_data<typename boost::remove_reference<F>::type> >( | |
216 | boost::forward<F>(f))); | |
217 | } | |
218 | #endif | |
219 | static inline detail::thread_data_ptr make_thread_info(void (*f)()) | |
220 | { | |
221 | return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >( | |
222 | boost::forward<void(*)()>(f))); | |
223 | } | |
224 | #else | |
225 | template<typename F> | |
226 | static inline detail::thread_data_ptr make_thread_info(F f | |
227 | , typename disable_if_c< | |
228 | //boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F)>::value || | |
229 | is_same<typename decay<F>::type, thread>::value, | |
230 | dummy* >::type=0 | |
231 | ) | |
232 | { | |
233 | return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f)); | |
234 | } | |
235 | template<typename F> | |
236 | static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f) | |
237 | { | |
238 | return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f)); | |
239 | } | |
240 | ||
241 | #endif | |
242 | public: | |
243 | #if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. | |
244 | #if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) | |
245 | thread(const volatile thread&); | |
246 | #endif | |
247 | #endif | |
248 | thread() BOOST_NOEXCEPT; | |
249 | ~thread() | |
250 | { | |
251 | ||
252 | #if defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE | |
253 | if (joinable()) { | |
254 | std::terminate(); | |
255 | } | |
256 | #else | |
257 | detach(); | |
258 | #endif | |
259 | } | |
260 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | |
261 | template < | |
262 | class F | |
263 | > | |
264 | explicit thread(BOOST_THREAD_RV_REF(F) f | |
265 | //, typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0 | |
266 | ): | |
267 | thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f)))) | |
268 | { | |
269 | start_thread(); | |
270 | } | |
271 | template < | |
272 | class F | |
273 | > | |
274 | thread(attributes const& attrs, BOOST_THREAD_RV_REF(F) f): | |
275 | thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f)))) | |
276 | { | |
277 | start_thread(attrs); | |
278 | } | |
279 | ||
280 | #else | |
281 | #ifdef BOOST_NO_SFINAE | |
282 | template <class F> | |
283 | explicit thread(F f): | |
284 | thread_info(make_thread_info(f)) | |
285 | { | |
286 | start_thread(); | |
287 | } | |
288 | template <class F> | |
289 | thread(attributes const& attrs, F f): | |
290 | thread_info(make_thread_info(f)) | |
291 | { | |
292 | start_thread(attrs); | |
293 | } | |
294 | #else | |
295 | template <class F> | |
296 | explicit thread(F f | |
297 | , typename disable_if_c< | |
298 | boost::thread_detail::is_rv<F>::value // todo as a thread_detail::is_rv | |
299 | //boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F)>::value | |
300 | //|| is_same<typename decay<F>::type, thread>::value | |
301 | , dummy* >::type=0 | |
302 | ): | |
303 | thread_info(make_thread_info(f)) | |
304 | { | |
305 | start_thread(); | |
306 | } | |
307 | template <class F> | |
308 | thread(attributes const& attrs, F f | |
309 | , typename disable_if<boost::thread_detail::is_rv<F>, dummy* >::type=0 | |
310 | //, typename disable_if<boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0 | |
311 | ): | |
312 | thread_info(make_thread_info(f)) | |
313 | { | |
314 | start_thread(attrs); | |
315 | } | |
316 | #endif | |
317 | template <class F> | |
318 | explicit thread(BOOST_THREAD_RV_REF(F) f | |
319 | , typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0 | |
320 | ): | |
321 | #ifdef BOOST_THREAD_USES_MOVE | |
322 | thread_info(make_thread_info(boost::move<F>(f))) // todo : Add forward | |
323 | #else | |
324 | thread_info(make_thread_info(f)) // todo : Add forward | |
325 | #endif | |
326 | { | |
327 | start_thread(); | |
328 | } | |
329 | ||
330 | template <class F> | |
331 | thread(attributes const& attrs, BOOST_THREAD_RV_REF(F) f): | |
332 | #ifdef BOOST_THREAD_USES_MOVE | |
333 | thread_info(make_thread_info(boost::move<F>(f))) // todo : Add forward | |
334 | #else | |
335 | thread_info(make_thread_info(f)) // todo : Add forward | |
336 | #endif | |
337 | { | |
338 | start_thread(attrs); | |
339 | } | |
340 | #endif | |
341 | thread(BOOST_THREAD_RV_REF(thread) x) BOOST_NOEXCEPT | |
342 | { | |
343 | thread_info=BOOST_THREAD_RV(x).thread_info; | |
344 | BOOST_THREAD_RV(x).thread_info.reset(); | |
345 | } | |
346 | #if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. | |
347 | #if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) | |
348 | thread& operator=(thread x) | |
349 | { | |
350 | swap(x); | |
351 | return *this; | |
352 | } | |
353 | #endif | |
354 | #endif | |
355 | ||
356 | thread& operator=(BOOST_THREAD_RV_REF(thread) other) BOOST_NOEXCEPT | |
357 | { | |
358 | ||
359 | #if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE | |
360 | if (joinable()) std::terminate(); | |
361 | #else | |
362 | detach(); | |
363 | #endif | |
364 | thread_info=BOOST_THREAD_RV(other).thread_info; | |
365 | BOOST_THREAD_RV(other).thread_info.reset(); | |
366 | return *this; | |
367 | } | |
368 | ||
369 | #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) | |
370 | template <class F, class Arg, class ...Args> | |
371 | thread(F&& f, Arg&& arg, Args&&... args) : | |
372 | thread_info(make_thread_info( | |
373 | thread_detail::decay_copy(boost::forward<F>(f)), | |
374 | thread_detail::decay_copy(boost::forward<Arg>(arg)), | |
375 | thread_detail::decay_copy(boost::forward<Args>(args))...) | |
376 | ) | |
377 | ||
378 | { | |
379 | start_thread(); | |
380 | } | |
381 | template <class F, class Arg, class ...Args> | |
382 | thread(attributes const& attrs, F&& f, Arg&& arg, Args&&... args) : | |
383 | thread_info(make_thread_info( | |
384 | thread_detail::decay_copy(boost::forward<F>(f)), | |
385 | thread_detail::decay_copy(boost::forward<Arg>(arg)), | |
386 | thread_detail::decay_copy(boost::forward<Args>(args))...) | |
387 | ) | |
388 | ||
389 | { | |
390 | start_thread(attrs); | |
391 | } | |
392 | #else | |
393 | template <class F,class A1> | |
394 | thread(F f,A1 a1,typename disable_if<boost::thread_detail::is_convertible<F&,thread_attributes >, dummy* >::type=0): | |
395 | thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1))) | |
396 | { | |
397 | start_thread(); | |
398 | } | |
399 | template <class F,class A1,class A2> | |
400 | thread(F f,A1 a1,A2 a2): | |
401 | thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2))) | |
402 | { | |
403 | start_thread(); | |
404 | } | |
405 | ||
406 | template <class F,class A1,class A2,class A3> | |
407 | thread(F f,A1 a1,A2 a2,A3 a3): | |
408 | thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3))) | |
409 | { | |
410 | start_thread(); | |
411 | } | |
412 | ||
413 | template <class F,class A1,class A2,class A3,class A4> | |
414 | thread(F f,A1 a1,A2 a2,A3 a3,A4 a4): | |
415 | thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4))) | |
416 | { | |
417 | start_thread(); | |
418 | } | |
419 | ||
420 | template <class F,class A1,class A2,class A3,class A4,class A5> | |
421 | thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5): | |
422 | thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5))) | |
423 | { | |
424 | start_thread(); | |
425 | } | |
426 | ||
427 | template <class F,class A1,class A2,class A3,class A4,class A5,class A6> | |
428 | thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6): | |
429 | thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6))) | |
430 | { | |
431 | start_thread(); | |
432 | } | |
433 | ||
434 | template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7> | |
435 | thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7): | |
436 | thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7))) | |
437 | { | |
438 | start_thread(); | |
439 | } | |
440 | ||
441 | template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8> | |
442 | thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8): | |
443 | thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8))) | |
444 | { | |
445 | start_thread(); | |
446 | } | |
447 | ||
448 | template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8,class A9> | |
449 | thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8,A9 a9): | |
450 | thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8,a9))) | |
451 | { | |
452 | start_thread(); | |
453 | } | |
454 | #endif | |
455 | void swap(thread& x) BOOST_NOEXCEPT | |
456 | { | |
457 | thread_info.swap(x.thread_info); | |
458 | } | |
459 | ||
460 | class id; | |
461 | id get_id() const BOOST_NOEXCEPT; | |
462 | ||
463 | bool joinable() const BOOST_NOEXCEPT; | |
464 | private: | |
465 | bool join_noexcept(); | |
466 | bool do_try_join_until_noexcept(detail::internal_platform_timepoint const &timeout, bool& res); | |
467 | bool do_try_join_until(detail::internal_platform_timepoint const &timeout); | |
468 | public: | |
469 | void join(); | |
470 | ||
471 | #ifdef BOOST_THREAD_USES_CHRONO | |
472 | template <class Duration> | |
473 | bool try_join_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t) | |
474 | { | |
475 | return do_try_join_until(boost::detail::internal_platform_timepoint(t)); | |
476 | } | |
477 | ||
478 | template <class Clock, class Duration> | |
479 | bool try_join_until(const chrono::time_point<Clock, Duration>& t) | |
480 | { | |
481 | typedef typename common_type<Duration, typename Clock::duration>::type common_duration; | |
482 | common_duration d(t - Clock::now()); | |
483 | d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); | |
484 | while ( ! try_join_until(detail::internal_chrono_clock::now() + d) ) | |
485 | { | |
486 | d = t - Clock::now(); | |
487 | if ( d <= common_duration::zero() ) return false; // timeout occurred | |
488 | d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); | |
489 | } | |
490 | return true; | |
491 | } | |
492 | ||
493 | template <class Rep, class Period> | |
494 | bool try_join_for(const chrono::duration<Rep, Period>& rel_time) | |
495 | { | |
496 | return try_join_until(chrono::steady_clock::now() + rel_time); | |
497 | } | |
498 | #endif | |
499 | #if defined BOOST_THREAD_USES_DATETIME | |
500 | bool timed_join(const system_time& abs_time) | |
501 | { | |
502 | const detail::real_platform_timepoint ts(abs_time); | |
503 | #if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO | |
504 | detail::platform_duration d(ts - detail::real_platform_clock::now()); | |
505 | d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); | |
506 | while ( ! do_try_join_until(detail::internal_platform_clock::now() + d) ) | |
507 | { | |
508 | d = ts - detail::real_platform_clock::now(); | |
509 | if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred | |
510 | d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); | |
511 | } | |
512 | return true; | |
513 | #else | |
514 | return do_try_join_until(ts); | |
515 | #endif | |
516 | } | |
517 | ||
518 | template<typename TimeDuration> | |
519 | bool timed_join(TimeDuration const& rel_time) | |
520 | { | |
521 | detail::platform_duration d(rel_time); | |
522 | #if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) | |
523 | const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d); | |
524 | d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); | |
525 | while ( ! do_try_join_until(detail::internal_platform_clock::now() + d) ) | |
526 | { | |
527 | d = ts - detail::mono_platform_clock::now(); | |
528 | if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred | |
529 | d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); | |
530 | } | |
531 | return true; | |
532 | #else | |
533 | return do_try_join_until(detail::internal_platform_clock::now() + d); | |
534 | #endif | |
535 | } | |
536 | #endif | |
537 | void detach(); | |
538 | ||
539 | static unsigned hardware_concurrency() BOOST_NOEXCEPT; | |
540 | static unsigned physical_concurrency() BOOST_NOEXCEPT; | |
541 | ||
542 | #define BOOST_THREAD_DEFINES_THREAD_NATIVE_HANDLE | |
543 | typedef detail::thread_data_base::native_handle_type native_handle_type; | |
544 | native_handle_type native_handle(); | |
545 | ||
546 | #if defined BOOST_THREAD_PROVIDES_THREAD_EQ | |
547 | // Use thread::id when comparisions are needed | |
548 | // backwards compatibility | |
549 | bool operator==(const thread& other) const; | |
550 | bool operator!=(const thread& other) const; | |
551 | #endif | |
552 | #if defined BOOST_THREAD_USES_DATETIME | |
553 | static inline void yield() BOOST_NOEXCEPT | |
554 | { | |
555 | this_thread::yield(); | |
556 | } | |
557 | ||
558 | static inline void sleep(const system_time& xt) | |
559 | { | |
560 | this_thread::sleep(xt); | |
561 | } | |
562 | #endif | |
563 | ||
564 | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | |
565 | // extensions | |
566 | void interrupt(); | |
567 | bool interruption_requested() const BOOST_NOEXCEPT; | |
568 | #endif | |
569 | }; | |
570 | ||
571 | inline void swap(thread& lhs,thread& rhs) BOOST_NOEXCEPT | |
572 | { | |
573 | return lhs.swap(rhs); | |
574 | } | |
575 | ||
576 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | |
577 | inline thread&& move(thread& t) BOOST_NOEXCEPT | |
578 | { | |
579 | return static_cast<thread&&>(t); | |
580 | } | |
581 | #endif | |
582 | ||
583 | BOOST_THREAD_DCL_MOVABLE(thread) | |
584 | ||
585 | namespace this_thread | |
586 | { | |
587 | #ifdef BOOST_THREAD_PLATFORM_PTHREAD | |
588 | thread::id get_id() BOOST_NOEXCEPT; | |
589 | #else | |
590 | thread::id BOOST_THREAD_DECL get_id() BOOST_NOEXCEPT; | |
591 | #endif | |
592 | ||
593 | #if defined BOOST_THREAD_USES_DATETIME | |
594 | inline BOOST_SYMBOL_VISIBLE void sleep(::boost::xtime const& abs_time) | |
595 | { | |
596 | sleep(system_time(abs_time)); | |
597 | } | |
598 | #endif | |
599 | } | |
600 | ||
601 | class BOOST_SYMBOL_VISIBLE thread::id | |
602 | { | |
603 | private: | |
604 | ||
605 | #if !defined(BOOST_EMBTC) | |
606 | ||
607 | friend inline | |
608 | std::size_t | |
609 | hash_value(const thread::id &v) | |
610 | { | |
611 | #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID | |
612 | return hash_value(v.thread_data); | |
613 | #else | |
614 | return hash_value(v.thread_data.get()); | |
615 | #endif | |
616 | } | |
617 | ||
618 | #else | |
619 | ||
620 | friend | |
621 | std::size_t | |
622 | hash_value(const thread::id &v); | |
623 | ||
624 | #endif | |
625 | ||
626 | #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID | |
627 | #if defined(BOOST_THREAD_PLATFORM_WIN32) | |
628 | typedef unsigned int data; | |
629 | #else | |
630 | typedef thread::native_handle_type data; | |
631 | #endif | |
632 | #else | |
633 | typedef detail::thread_data_ptr data; | |
634 | #endif | |
635 | data thread_data; | |
636 | ||
637 | id(data thread_data_): | |
638 | thread_data(thread_data_) | |
639 | {} | |
640 | friend class thread; | |
641 | friend id BOOST_THREAD_DECL this_thread::get_id() BOOST_NOEXCEPT; | |
642 | public: | |
643 | id() BOOST_NOEXCEPT: | |
644 | #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID | |
645 | thread_data(0) | |
646 | #else | |
647 | thread_data() | |
648 | #endif | |
649 | {} | |
650 | ||
651 | bool operator==(const id& y) const BOOST_NOEXCEPT | |
652 | { | |
653 | return thread_data==y.thread_data; | |
654 | } | |
655 | ||
656 | bool operator!=(const id& y) const BOOST_NOEXCEPT | |
657 | { | |
658 | return thread_data!=y.thread_data; | |
659 | } | |
660 | ||
661 | bool operator<(const id& y) const BOOST_NOEXCEPT | |
662 | { | |
663 | return thread_data<y.thread_data; | |
664 | } | |
665 | ||
666 | bool operator>(const id& y) const BOOST_NOEXCEPT | |
667 | { | |
668 | return y.thread_data<thread_data; | |
669 | } | |
670 | ||
671 | bool operator<=(const id& y) const BOOST_NOEXCEPT | |
672 | { | |
673 | return !(y.thread_data<thread_data); | |
674 | } | |
675 | ||
676 | bool operator>=(const id& y) const BOOST_NOEXCEPT | |
677 | { | |
678 | return !(thread_data<y.thread_data); | |
679 | } | |
680 | ||
681 | #ifndef BOOST_NO_IOSTREAM | |
682 | #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS | |
683 | template<class charT, class traits> | |
684 | friend BOOST_SYMBOL_VISIBLE | |
685 | std::basic_ostream<charT, traits>& | |
686 | operator<<(std::basic_ostream<charT, traits>& os, const id& x) | |
687 | { | |
688 | if(x.thread_data) | |
689 | { | |
690 | io::ios_flags_saver ifs( os ); | |
691 | return os<< std::hex << x.thread_data; | |
692 | } | |
693 | else | |
694 | { | |
695 | return os<<"{Not-any-thread}"; | |
696 | } | |
697 | } | |
698 | #else | |
699 | template<class charT, class traits> | |
700 | BOOST_SYMBOL_VISIBLE | |
701 | std::basic_ostream<charT, traits>& | |
702 | print(std::basic_ostream<charT, traits>& os) const | |
703 | { | |
704 | if(thread_data) | |
705 | { | |
706 | io::ios_flags_saver ifs( os ); | |
707 | return os<< std::hex << thread_data; | |
708 | } | |
709 | else | |
710 | { | |
711 | return os<<"{Not-any-thread}"; | |
712 | } | |
713 | } | |
714 | ||
715 | #endif | |
716 | #endif | |
717 | }; | |
718 | ||
719 | #if defined(BOOST_EMBTC) | |
720 | ||
721 | inline | |
722 | std::size_t | |
723 | hash_value(const thread::id &v) | |
724 | { | |
725 | #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID | |
726 | return hash_value(v.thread_data); | |
727 | #else | |
728 | return hash_value(v.thread_data.get()); | |
729 | #endif | |
730 | } | |
731 | ||
732 | #endif | |
733 | ||
734 | #ifdef BOOST_THREAD_PLATFORM_PTHREAD | |
735 | inline thread::id thread::get_id() const BOOST_NOEXCEPT | |
736 | { | |
737 | #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID | |
738 | return const_cast<thread*>(this)->native_handle(); | |
739 | #else | |
740 | detail::thread_data_ptr const local_thread_info=(get_thread_info)(); | |
741 | return (local_thread_info? id(local_thread_info) : id()); | |
742 | #endif | |
743 | } | |
744 | ||
745 | namespace this_thread | |
746 | { | |
747 | inline thread::id get_id() BOOST_NOEXCEPT | |
748 | { | |
749 | #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID | |
750 | return pthread_self(); | |
751 | #else | |
752 | boost::detail::thread_data_base* const thread_info=get_or_make_current_thread_data(); | |
753 | return (thread_info?thread::id(thread_info->shared_from_this()):thread::id()); | |
754 | #endif | |
755 | } | |
756 | } | |
757 | #endif | |
758 | inline void thread::join() { | |
759 | if (this_thread::get_id() == get_id()) | |
760 | boost::throw_exception(thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself")); | |
761 | ||
762 | BOOST_THREAD_VERIFY_PRECONDITION( join_noexcept(), | |
763 | thread_resource_error(static_cast<int>(system::errc::invalid_argument), "boost thread: thread not joinable") | |
764 | ); | |
765 | } | |
766 | ||
767 | inline bool thread::do_try_join_until(detail::internal_platform_timepoint const &timeout) | |
768 | { | |
769 | if (this_thread::get_id() == get_id()) | |
770 | boost::throw_exception(thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself")); | |
771 | bool res; | |
772 | if (do_try_join_until_noexcept(timeout, res)) | |
773 | { | |
774 | return res; | |
775 | } | |
776 | else | |
777 | { | |
778 | BOOST_THREAD_THROW_ELSE_RETURN( | |
779 | (thread_resource_error(static_cast<int>(system::errc::invalid_argument), "boost thread: thread not joinable")), | |
780 | false | |
781 | ); | |
782 | } | |
783 | } | |
784 | ||
785 | #if !defined(BOOST_NO_IOSTREAM) && defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) | |
786 | template<class charT, class traits> | |
787 | BOOST_SYMBOL_VISIBLE | |
788 | std::basic_ostream<charT, traits>& | |
789 | operator<<(std::basic_ostream<charT, traits>& os, const thread::id& x) | |
790 | { | |
791 | return x.print(os); | |
792 | } | |
793 | #endif | |
794 | ||
795 | #if defined BOOST_THREAD_PROVIDES_THREAD_EQ | |
796 | inline bool thread::operator==(const thread& other) const | |
797 | { | |
798 | return get_id()==other.get_id(); | |
799 | } | |
800 | ||
801 | inline bool thread::operator!=(const thread& other) const | |
802 | { | |
803 | return get_id()!=other.get_id(); | |
804 | } | |
805 | #endif | |
806 | ||
807 | namespace detail | |
808 | { | |
809 | struct thread_exit_function_base | |
810 | { | |
811 | virtual ~thread_exit_function_base() | |
812 | {} | |
813 | virtual void operator()()=0; | |
814 | }; | |
815 | ||
816 | template<typename F> | |
817 | struct thread_exit_function: | |
818 | thread_exit_function_base | |
819 | { | |
820 | F f; | |
821 | ||
822 | thread_exit_function(F f_): | |
823 | f(f_) | |
824 | {} | |
825 | ||
826 | void operator()() | |
827 | { | |
828 | f(); | |
829 | } | |
830 | }; | |
831 | ||
832 | void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*); | |
833 | //#ifndef BOOST_NO_EXCEPTIONS | |
834 | struct shared_state_base; | |
835 | #if defined(BOOST_THREAD_PLATFORM_WIN32) | |
836 | inline void make_ready_at_thread_exit(shared_ptr<shared_state_base> as) | |
837 | { | |
838 | detail::thread_data_base* const current_thread_data(detail::get_current_thread_data()); | |
839 | if(current_thread_data) | |
840 | { | |
841 | current_thread_data->make_ready_at_thread_exit(as); | |
842 | } | |
843 | } | |
844 | #else | |
845 | void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as); | |
846 | #endif | |
847 | //#endif | |
848 | } | |
849 | ||
850 | namespace this_thread | |
851 | { | |
852 | template<typename F> | |
853 | void at_thread_exit(F f) | |
854 | { | |
855 | detail::thread_exit_function_base* const thread_exit_func=detail::heap_new<detail::thread_exit_function<F> >(f); | |
856 | detail::add_thread_exit_function(thread_exit_func); | |
857 | } | |
858 | } | |
859 | } | |
860 | ||
861 | #ifdef BOOST_MSVC | |
862 | #pragma warning(pop) | |
863 | #endif | |
864 | ||
865 | #include <boost/config/abi_suffix.hpp> | |
866 | ||
867 | #endif |