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
9 #include <boost/thread/detail/config.hpp>
10 #include <boost/predef/platform.h>
12 #include <boost/thread/exceptions.hpp>
13 #ifndef BOOST_NO_IOSTREAM
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>
21 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
22 #include <boost/thread/interruption.hpp>
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>
31 #include <boost/core/ref.hpp>
32 #include <boost/cstdint.hpp>
33 #include <boost/bind/bind.hpp>
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>
48 #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
51 #include <boost/config/abi_prefix.hpp>
55 #pragma warning(disable:4251)
64 #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
66 template<typename F, class ...ArgTypes>
68 public detail::thread_data_base
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_)...)
75 template <std::size_t ...Indices>
76 void run2(tuple_indices<Indices...>)
79 detail::invoke(std::move(std::get<0>(fp)), std::move(std::get<Indices>(fp))...);
83 typedef typename make_tuple_indices<std::tuple_size<std::tuple<F, ArgTypes...> >::value, 1>::type index_type;
89 std::tuple<typename decay<F>::type, typename decay<ArgTypes>::type...> fp;
91 #else // defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
95 public detail::thread_data_base
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_))
103 // This overloading must be removed if we want the packaged_task's tests to pass.
104 // thread_data(F& f_):
109 thread_data(BOOST_THREAD_RV_REF(F) f_):
128 class thread_data<boost::reference_wrapper<F> >:
129 public detail::thread_data_base
134 BOOST_THREAD_NO_COPYABLE(thread_data)
135 thread_data(boost::reference_wrapper<F> f_):
145 class thread_data<const boost::reference_wrapper<F> >:
146 public detail::thread_data_base
151 BOOST_THREAD_NO_COPYABLE(thread_data)
152 thread_data(const boost::reference_wrapper<F> f_):
163 class BOOST_THREAD_DECL thread
166 typedef thread_attributes attributes;
168 BOOST_THREAD_MOVABLE_ONLY(thread)
173 void release_handle();
175 detail::thread_data_ptr thread_info;
178 bool start_thread_noexcept();
179 bool start_thread_noexcept(const attributes& attr);
182 if (!start_thread_noexcept())
184 boost::throw_exception(thread_resource_error());
187 void start_thread(const attributes& attr)
189 if (!start_thread_noexcept(attr))
191 boost::throw_exception(thread_resource_error());
195 explicit thread(detail::thread_data_ptr data);
197 detail::thread_data_ptr get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const;
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)
204 return detail::thread_data_ptr(detail::heap_new<
205 detail::thread_data<typename boost::remove_reference<F>::type, ArgTypes...>
207 boost::forward<F>(f), boost::forward<ArgTypes>(args)...
213 static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f)
215 return detail::thread_data_ptr(detail::heap_new<detail::thread_data<typename boost::remove_reference<F>::type> >(
216 boost::forward<F>(f)));
219 static inline detail::thread_data_ptr make_thread_info(void (*f)())
221 return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >(
222 boost::forward<void(*)()>(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,
233 return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
236 static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f)
238 return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
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&);
248 thread() BOOST_NOEXCEPT;
252 #if defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
260 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
264 explicit thread(BOOST_THREAD_RV_REF(F) f
265 //, typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0
267 thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f))))
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))))
281 #ifdef BOOST_NO_SFINAE
283 explicit thread(F f):
284 thread_info(make_thread_info(f))
289 thread(attributes const& attrs, F f):
290 thread_info(make_thread_info(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
303 thread_info(make_thread_info(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
312 thread_info(make_thread_info(f))
318 explicit thread(BOOST_THREAD_RV_REF(F) f
319 , typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0
321 #ifdef BOOST_THREAD_USES_MOVE
322 thread_info(make_thread_info(boost::move<F>(f))) // todo : Add forward
324 thread_info(make_thread_info(f)) // todo : Add forward
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
335 thread_info(make_thread_info(f)) // todo : Add forward
341 thread(BOOST_THREAD_RV_REF(thread) x) BOOST_NOEXCEPT
343 thread_info=BOOST_THREAD_RV(x).thread_info;
344 BOOST_THREAD_RV(x).thread_info.reset();
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)
356 thread& operator=(BOOST_THREAD_RV_REF(thread) other) BOOST_NOEXCEPT
359 #if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
360 if (joinable()) std::terminate();
364 thread_info=BOOST_THREAD_RV(other).thread_info;
365 BOOST_THREAD_RV(other).thread_info.reset();
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))...)
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))...)
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)))
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)))
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)))
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)))
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)))
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)))
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)))
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)))
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)))
455 void swap(thread& x) BOOST_NOEXCEPT
457 thread_info.swap(x.thread_info);
461 id get_id() const BOOST_NOEXCEPT;
463 bool joinable() const BOOST_NOEXCEPT;
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);
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)
475 return do_try_join_until(boost::detail::internal_platform_timepoint(t));
478 template <class Clock, class Duration>
479 bool try_join_until(const chrono::time_point<Clock, Duration>& t)
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) )
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)));
493 template <class Rep, class Period>
494 bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
496 return try_join_until(chrono::steady_clock::now() + rel_time);
499 #if defined BOOST_THREAD_USES_DATETIME
500 bool timed_join(const system_time& abs_time)
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) )
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));
514 return do_try_join_until(ts);
518 template<typename TimeDuration>
519 bool timed_join(TimeDuration const& rel_time)
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) )
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));
533 return do_try_join_until(detail::internal_platform_clock::now() + d);
539 static unsigned hardware_concurrency() BOOST_NOEXCEPT;
540 static unsigned physical_concurrency() BOOST_NOEXCEPT;
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();
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;
552 #if defined BOOST_THREAD_USES_DATETIME
553 static inline void yield() BOOST_NOEXCEPT
555 this_thread::yield();
558 static inline void sleep(const system_time& xt)
560 this_thread::sleep(xt);
564 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
567 bool interruption_requested() const BOOST_NOEXCEPT;
571 inline void swap(thread& lhs,thread& rhs) BOOST_NOEXCEPT
573 return lhs.swap(rhs);
576 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
577 inline thread&& move(thread& t) BOOST_NOEXCEPT
579 return static_cast<thread&&>(t);
583 BOOST_THREAD_DCL_MOVABLE(thread)
585 namespace this_thread
587 #ifdef BOOST_THREAD_PLATFORM_PTHREAD
588 thread::id get_id() BOOST_NOEXCEPT;
590 thread::id BOOST_THREAD_DECL get_id() BOOST_NOEXCEPT;
593 #if defined BOOST_THREAD_USES_DATETIME
594 inline BOOST_SYMBOL_VISIBLE void sleep(::boost::xtime const& abs_time)
596 sleep(system_time(abs_time));
601 class BOOST_SYMBOL_VISIBLE thread::id
605 #if !defined(BOOST_EMBTC)
609 hash_value(const thread::id &v)
611 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
612 return hash_value(v.thread_data);
614 return hash_value(v.thread_data.get());
622 hash_value(const thread::id &v);
626 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
627 #if defined(BOOST_THREAD_PLATFORM_WIN32)
628 typedef unsigned int data;
630 typedef thread::native_handle_type data;
633 typedef detail::thread_data_ptr data;
637 id(data thread_data_):
638 thread_data(thread_data_)
641 friend id BOOST_THREAD_DECL this_thread::get_id() BOOST_NOEXCEPT;
644 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
651 bool operator==(const id& y) const BOOST_NOEXCEPT
653 return thread_data==y.thread_data;
656 bool operator!=(const id& y) const BOOST_NOEXCEPT
658 return thread_data!=y.thread_data;
661 bool operator<(const id& y) const BOOST_NOEXCEPT
663 return thread_data<y.thread_data;
666 bool operator>(const id& y) const BOOST_NOEXCEPT
668 return y.thread_data<thread_data;
671 bool operator<=(const id& y) const BOOST_NOEXCEPT
673 return !(y.thread_data<thread_data);
676 bool operator>=(const id& y) const BOOST_NOEXCEPT
678 return !(thread_data<y.thread_data);
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)
690 io::ios_flags_saver ifs( os );
691 return os<< std::hex << x.thread_data;
695 return os<<"{Not-any-thread}";
699 template<class charT, class traits>
701 std::basic_ostream<charT, traits>&
702 print(std::basic_ostream<charT, traits>& os) const
706 io::ios_flags_saver ifs( os );
707 return os<< std::hex << thread_data;
711 return os<<"{Not-any-thread}";
719 #if defined(BOOST_EMBTC)
723 hash_value(const thread::id &v)
725 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
726 return hash_value(v.thread_data);
728 return hash_value(v.thread_data.get());
734 #ifdef BOOST_THREAD_PLATFORM_PTHREAD
735 inline thread::id thread::get_id() const BOOST_NOEXCEPT
737 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
738 return const_cast<thread*>(this)->native_handle();
740 detail::thread_data_ptr const local_thread_info=(get_thread_info)();
741 return (local_thread_info? id(local_thread_info) : id());
745 namespace this_thread
747 inline thread::id get_id() BOOST_NOEXCEPT
749 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
750 return pthread_self();
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());
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"));
762 BOOST_THREAD_VERIFY_PRECONDITION( join_noexcept(),
763 thread_resource_error(static_cast<int>(system::errc::invalid_argument), "boost thread: thread not joinable")
767 inline bool thread::do_try_join_until(detail::internal_platform_timepoint const &timeout)
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"));
772 if (do_try_join_until_noexcept(timeout, res))
778 BOOST_THREAD_THROW_ELSE_RETURN(
779 (thread_resource_error(static_cast<int>(system::errc::invalid_argument), "boost thread: thread not joinable")),
785 #if !defined(BOOST_NO_IOSTREAM) && defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
786 template<class charT, class traits>
788 std::basic_ostream<charT, traits>&
789 operator<<(std::basic_ostream<charT, traits>& os, const thread::id& x)
795 #if defined BOOST_THREAD_PROVIDES_THREAD_EQ
796 inline bool thread::operator==(const thread& other) const
798 return get_id()==other.get_id();
801 inline bool thread::operator!=(const thread& other) const
803 return get_id()!=other.get_id();
809 struct thread_exit_function_base
811 virtual ~thread_exit_function_base()
813 virtual void operator()()=0;
817 struct thread_exit_function:
818 thread_exit_function_base
822 thread_exit_function(F f_):
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)
838 detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
839 if(current_thread_data)
841 current_thread_data->make_ready_at_thread_exit(as);
845 void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as);
850 namespace this_thread
853 void at_thread_exit(F f)
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);
865 #include <boost/config/abi_suffix.hpp>