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 #include <boost/thread/detail/thread_heap_alloc.hpp>
22 #include <boost/thread/detail/make_tuple_indices.hpp>
23 #include <boost/thread/detail/invoke.hpp>
24 #include <boost/thread/detail/is_convertible.hpp>
25 #include <boost/assert.hpp>
28 #include <boost/core/ref.hpp>
29 #include <boost/cstdint.hpp>
30 #include <boost/bind.hpp>
33 #include <boost/core/enable_if.hpp>
34 #include <boost/type_traits/remove_reference.hpp>
35 #include <boost/io/ios_state.hpp>
36 #include <boost/type_traits/is_same.hpp>
37 #include <boost/type_traits/decay.hpp>
38 #include <boost/functional/hash.hpp>
39 #ifdef BOOST_THREAD_USES_CHRONO
40 #include <boost/chrono/system_clocks.hpp>
41 #include <boost/chrono/ceil.hpp>
44 #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
47 #include <boost/config/abi_prefix.hpp>
51 #pragma warning(disable:4251)
60 #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
62 template<typename F, class ...ArgTypes>
64 public detail::thread_data_base
67 BOOST_THREAD_NO_COPYABLE(thread_data)
68 thread_data(BOOST_THREAD_RV_REF(F) f_, BOOST_THREAD_RV_REF(ArgTypes)... args_):
69 fp(boost::forward<F>(f_), boost::forward<ArgTypes>(args_)...)
71 template <std::size_t ...Indices>
72 void run2(tuple_indices<Indices...>)
75 detail::invoke(std::move(std::get<0>(fp)), std::move(std::get<Indices>(fp))...);
79 typedef typename make_tuple_indices<std::tuple_size<std::tuple<F, ArgTypes...> >::value, 1>::type index_type;
85 std::tuple<typename decay<F>::type, typename decay<ArgTypes>::type...> fp;
87 #else // defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
91 public detail::thread_data_base
94 BOOST_THREAD_NO_COPYABLE(thread_data)
95 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
96 thread_data(BOOST_THREAD_RV_REF(F) f_):
97 f(boost::forward<F>(f_))
99 // This overloading must be removed if we want the packaged_task's tests to pass.
100 // thread_data(F& f_):
105 thread_data(BOOST_THREAD_RV_REF(F) f_):
124 class thread_data<boost::reference_wrapper<F> >:
125 public detail::thread_data_base
130 BOOST_THREAD_NO_COPYABLE(thread_data)
131 thread_data(boost::reference_wrapper<F> f_):
141 class thread_data<const boost::reference_wrapper<F> >:
142 public detail::thread_data_base
147 BOOST_THREAD_NO_COPYABLE(thread_data)
148 thread_data(const boost::reference_wrapper<F> f_):
158 namespace thread_detail {
159 #ifdef BOOST_THREAD_USES_CHRONO
160 #if defined(BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC)
161 typedef chrono::steady_clock internal_clock_t;
163 typedef chrono::system_clock internal_clock_t;
167 class BOOST_THREAD_DECL thread
170 typedef thread_attributes attributes;
172 BOOST_THREAD_MOVABLE_ONLY(thread)
177 void release_handle();
179 detail::thread_data_ptr thread_info;
182 bool start_thread_noexcept();
183 bool start_thread_noexcept(const attributes& attr);
186 if (!start_thread_noexcept())
188 boost::throw_exception(thread_resource_error());
191 void start_thread(const attributes& attr)
193 if (!start_thread_noexcept(attr))
195 boost::throw_exception(thread_resource_error());
199 explicit thread(detail::thread_data_ptr data);
201 detail::thread_data_ptr get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const;
203 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
204 #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
205 template<typename F, class ...ArgTypes>
206 static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_RV_REF(ArgTypes)... args)
208 return detail::thread_data_ptr(detail::heap_new<
209 detail::thread_data<typename boost::remove_reference<F>::type, ArgTypes...>
211 boost::forward<F>(f), boost::forward<ArgTypes>(args)...
217 static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f)
219 return detail::thread_data_ptr(detail::heap_new<detail::thread_data<typename boost::remove_reference<F>::type> >(
220 boost::forward<F>(f)));
223 static inline detail::thread_data_ptr make_thread_info(void (*f)())
225 return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >(
226 boost::forward<void(*)()>(f)));
230 static inline detail::thread_data_ptr make_thread_info(F f
231 , typename disable_if_c<
232 //boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F)>::value ||
233 is_same<typename decay<F>::type, thread>::value,
237 return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
240 static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f)
242 return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
247 #if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF.
248 #if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
249 thread(const volatile thread&);
252 thread() BOOST_NOEXCEPT;
256 #if defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
264 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
268 explicit thread(BOOST_THREAD_RV_REF(F) f
269 //, typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0
271 thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f))))
278 thread(attributes const& attrs, BOOST_THREAD_RV_REF(F) f):
279 thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f))))
285 #ifdef BOOST_NO_SFINAE
287 explicit thread(F f):
288 thread_info(make_thread_info(f))
293 thread(attributes const& attrs, F f):
294 thread_info(make_thread_info(f))
301 , typename disable_if_c<
302 boost::thread_detail::is_rv<F>::value // todo as a thread_detail::is_rv
303 //boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F)>::value
304 //|| is_same<typename decay<F>::type, thread>::value
307 thread_info(make_thread_info(f))
312 thread(attributes const& attrs, F f
313 , typename disable_if<boost::thread_detail::is_rv<F>, dummy* >::type=0
314 //, typename disable_if<boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0
316 thread_info(make_thread_info(f))
322 explicit thread(BOOST_THREAD_RV_REF(F) f
323 , typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0
325 #ifdef BOOST_THREAD_USES_MOVE
326 thread_info(make_thread_info(boost::move<F>(f))) // todo : Add forward
328 thread_info(make_thread_info(f)) // todo : Add forward
335 thread(attributes const& attrs, BOOST_THREAD_RV_REF(F) f):
336 #ifdef BOOST_THREAD_USES_MOVE
337 thread_info(make_thread_info(boost::move<F>(f))) // todo : Add forward
339 thread_info(make_thread_info(f)) // todo : Add forward
345 thread(BOOST_THREAD_RV_REF(thread) x) BOOST_NOEXCEPT
347 thread_info=BOOST_THREAD_RV(x).thread_info;
348 BOOST_THREAD_RV(x).thread_info.reset();
350 #if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF.
351 #if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
352 thread& operator=(thread x)
360 thread& operator=(BOOST_THREAD_RV_REF(thread) other) BOOST_NOEXCEPT
363 #if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
364 if (joinable()) std::terminate();
368 thread_info=BOOST_THREAD_RV(other).thread_info;
369 BOOST_THREAD_RV(other).thread_info.reset();
373 #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
374 template <class F, class Arg, class ...Args>
375 thread(F&& f, Arg&& arg, Args&&... args) :
376 thread_info(make_thread_info(
377 thread_detail::decay_copy(boost::forward<F>(f)),
378 thread_detail::decay_copy(boost::forward<Arg>(arg)),
379 thread_detail::decay_copy(boost::forward<Args>(args))...)
385 template <class F, class Arg, class ...Args>
386 thread(attributes const& attrs, F&& f, Arg&& arg, Args&&... args) :
387 thread_info(make_thread_info(
388 thread_detail::decay_copy(boost::forward<F>(f)),
389 thread_detail::decay_copy(boost::forward<Arg>(arg)),
390 thread_detail::decay_copy(boost::forward<Args>(args))...)
397 template <class F,class A1>
398 thread(F f,A1 a1,typename disable_if<boost::thread_detail::is_convertible<F&,thread_attributes >, dummy* >::type=0):
399 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1)))
403 template <class F,class A1,class A2>
404 thread(F f,A1 a1,A2 a2):
405 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2)))
410 template <class F,class A1,class A2,class A3>
411 thread(F f,A1 a1,A2 a2,A3 a3):
412 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3)))
417 template <class F,class A1,class A2,class A3,class A4>
418 thread(F f,A1 a1,A2 a2,A3 a3,A4 a4):
419 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4)))
424 template <class F,class A1,class A2,class A3,class A4,class A5>
425 thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5):
426 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5)))
431 template <class F,class A1,class A2,class A3,class A4,class A5,class A6>
432 thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6):
433 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6)))
438 template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7>
439 thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7):
440 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7)))
445 template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8>
446 thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8):
447 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8)))
452 template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8,class A9>
453 thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8,A9 a9):
454 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8,a9)))
459 void swap(thread& x) BOOST_NOEXCEPT
461 thread_info.swap(x.thread_info);
465 #ifdef BOOST_THREAD_PLATFORM_PTHREAD
466 inline id get_id() const BOOST_NOEXCEPT;
468 id get_id() const BOOST_NOEXCEPT;
472 bool joinable() const BOOST_NOEXCEPT;
474 bool join_noexcept();
478 #ifdef BOOST_THREAD_USES_CHRONO
479 #if defined(BOOST_THREAD_PLATFORM_WIN32)
480 template <class Rep, class Period>
481 bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
483 chrono::milliseconds rel_time2= chrono::ceil<chrono::milliseconds>(rel_time);
484 return do_try_join_until(rel_time2.count());
487 template <class Rep, class Period>
488 bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
490 return try_join_until(chrono::steady_clock::now() + rel_time);
494 template <class Clock, class Duration>
495 bool try_join_until(const chrono::time_point<Clock, Duration>& t)
497 using namespace chrono;
500 thread_detail::internal_clock_t::time_point s_now = thread_detail::internal_clock_t::now();
501 typename Clock::duration d = ceil<nanoseconds>(t-Clock::now());
502 if (d <= Clock::duration::zero()) return false; // in case the Clock::time_point t is already reached
503 joined = try_join_until(s_now + d);
507 template <class Duration>
508 bool try_join_until(const chrono::time_point<thread_detail::internal_clock_t, Duration>& t)
510 using namespace chrono;
511 typedef time_point<thread_detail::internal_clock_t, nanoseconds> nano_sys_tmpt;
512 return try_join_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
515 #if defined(BOOST_THREAD_PLATFORM_WIN32)
517 bool do_try_join_until_noexcept(uintmax_t milli, bool& res);
518 inline bool do_try_join_until(uintmax_t milli);
520 bool timed_join(const system_time& abs_time);
522 // return do_try_join_until(get_milliseconds_until(wait_until));
525 #ifdef BOOST_THREAD_USES_CHRONO
526 bool try_join_until(const chrono::time_point<thread_detail::internal_clock_t, chrono::nanoseconds>& tp)
528 chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
529 return do_try_join_until(rel_time.count());
536 bool do_try_join_until_noexcept(struct timespec const &timeout, bool& res);
537 inline bool do_try_join_until(struct timespec const &timeout);
539 #if defined BOOST_THREAD_USES_DATETIME
540 bool timed_join(const system_time& abs_time)
542 struct timespec const ts=detail::to_timespec(abs_time);
543 return do_try_join_until(ts);
546 #ifdef BOOST_THREAD_USES_CHRONO
547 bool try_join_until(const chrono::time_point<thread_detail::internal_clock_t, chrono::nanoseconds>& tp)
549 using namespace chrono;
550 nanoseconds d = tp.time_since_epoch();
551 timespec ts = boost::detail::to_timespec(d);
552 return do_try_join_until(ts);
559 #if defined BOOST_THREAD_USES_DATETIME
560 template<typename TimeDuration>
561 inline bool timed_join(TimeDuration const& rel_time)
563 return timed_join(get_system_time()+rel_time);
568 static unsigned hardware_concurrency() BOOST_NOEXCEPT;
569 static unsigned physical_concurrency() BOOST_NOEXCEPT;
571 #define BOOST_THREAD_DEFINES_THREAD_NATIVE_HANDLE
572 typedef detail::thread_data_base::native_handle_type native_handle_type;
573 native_handle_type native_handle();
575 #if defined BOOST_THREAD_PROVIDES_THREAD_EQ
576 // Use thread::id when comparisions are needed
577 // backwards compatibility
578 bool operator==(const thread& other) const;
579 bool operator!=(const thread& other) const;
581 #if defined BOOST_THREAD_USES_DATETIME
582 static inline void yield() BOOST_NOEXCEPT
584 this_thread::yield();
587 static inline void sleep(const system_time& xt)
589 this_thread::sleep(xt);
593 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
596 bool interruption_requested() const BOOST_NOEXCEPT;
600 inline void swap(thread& lhs,thread& rhs) BOOST_NOEXCEPT
602 return lhs.swap(rhs);
605 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
606 inline thread&& move(thread& t) BOOST_NOEXCEPT
608 return static_cast<thread&&>(t);
612 BOOST_THREAD_DCL_MOVABLE(thread)
614 namespace this_thread
616 #ifdef BOOST_THREAD_PLATFORM_PTHREAD
617 inline thread::id get_id() BOOST_NOEXCEPT;
619 thread::id BOOST_THREAD_DECL get_id() BOOST_NOEXCEPT;
622 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
623 void BOOST_THREAD_DECL interruption_point();
624 bool BOOST_THREAD_DECL interruption_enabled() BOOST_NOEXCEPT;
625 bool BOOST_THREAD_DECL interruption_requested() BOOST_NOEXCEPT;
628 #if defined BOOST_THREAD_USES_DATETIME
629 inline BOOST_SYMBOL_VISIBLE void sleep(xtime const& abs_time)
631 sleep(system_time(abs_time));
636 class BOOST_SYMBOL_VISIBLE thread::id
641 hash_value(const thread::id &v)
643 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
644 return hash_value(v.thread_data);
646 return hash_value(v.thread_data.get());
650 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
651 #if defined(BOOST_THREAD_PLATFORM_WIN32)
652 typedef unsigned int data;
654 typedef thread::native_handle_type data;
657 typedef detail::thread_data_ptr data;
661 id(data thread_data_):
662 thread_data(thread_data_)
665 friend id BOOST_THREAD_DECL this_thread::get_id() BOOST_NOEXCEPT;
668 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
675 id(const id& other) BOOST_NOEXCEPT :
676 thread_data(other.thread_data)
679 bool operator==(const id& y) const BOOST_NOEXCEPT
681 return thread_data==y.thread_data;
684 bool operator!=(const id& y) const BOOST_NOEXCEPT
686 return thread_data!=y.thread_data;
689 bool operator<(const id& y) const BOOST_NOEXCEPT
691 return thread_data<y.thread_data;
694 bool operator>(const id& y) const BOOST_NOEXCEPT
696 return y.thread_data<thread_data;
699 bool operator<=(const id& y) const BOOST_NOEXCEPT
701 return !(y.thread_data<thread_data);
704 bool operator>=(const id& y) const BOOST_NOEXCEPT
706 return !(thread_data<y.thread_data);
709 #ifndef BOOST_NO_IOSTREAM
710 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
711 template<class charT, class traits>
712 friend BOOST_SYMBOL_VISIBLE
713 std::basic_ostream<charT, traits>&
714 operator<<(std::basic_ostream<charT, traits>& os, const id& x)
718 io::ios_flags_saver ifs( os );
719 return os<< std::hex << x.thread_data;
723 return os<<"{Not-any-thread}";
727 template<class charT, class traits>
729 std::basic_ostream<charT, traits>&
730 print(std::basic_ostream<charT, traits>& os) const
734 io::ios_flags_saver ifs( os );
735 return os<< std::hex << thread_data;
739 return os<<"{Not-any-thread}";
747 #ifdef BOOST_THREAD_PLATFORM_PTHREAD
748 thread::id thread::get_id() const BOOST_NOEXCEPT
750 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
751 return const_cast<thread*>(this)->native_handle();
753 detail::thread_data_ptr const local_thread_info=(get_thread_info)();
754 return (local_thread_info? id(local_thread_info) : id());
758 namespace this_thread
760 inline thread::id get_id() BOOST_NOEXCEPT
762 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
763 return pthread_self();
765 boost::detail::thread_data_base* const thread_info=get_or_make_current_thread_data();
766 return (thread_info?thread::id(thread_info->shared_from_this()):thread::id());
771 void thread::join() {
772 if (this_thread::get_id() == get_id())
773 boost::throw_exception(thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself"));
775 BOOST_THREAD_VERIFY_PRECONDITION( join_noexcept(),
776 thread_resource_error(static_cast<int>(system::errc::invalid_argument), "boost thread: thread not joinable")
780 #ifdef BOOST_THREAD_PLATFORM_PTHREAD
781 bool thread::do_try_join_until(struct timespec const &timeout)
783 bool thread::do_try_join_until(uintmax_t timeout)
786 if (this_thread::get_id() == get_id())
787 boost::throw_exception(thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself"));
789 if (do_try_join_until_noexcept(timeout, res))
795 BOOST_THREAD_THROW_ELSE_RETURN(
796 (thread_resource_error(static_cast<int>(system::errc::invalid_argument), "boost thread: thread not joinable")),
802 #if !defined(BOOST_NO_IOSTREAM) && defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
803 template<class charT, class traits>
805 std::basic_ostream<charT, traits>&
806 operator<<(std::basic_ostream<charT, traits>& os, const thread::id& x)
812 #if defined BOOST_THREAD_PROVIDES_THREAD_EQ
813 inline bool thread::operator==(const thread& other) const
815 return get_id()==other.get_id();
818 inline bool thread::operator!=(const thread& other) const
820 return get_id()!=other.get_id();
826 struct thread_exit_function_base
828 virtual ~thread_exit_function_base()
830 virtual void operator()()=0;
834 struct thread_exit_function:
835 thread_exit_function_base
839 thread_exit_function(F f_):
849 void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*);
850 struct shared_state_base;
851 #if defined(BOOST_THREAD_PLATFORM_WIN32)
852 inline void make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
854 detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
855 if(current_thread_data)
857 current_thread_data->make_ready_at_thread_exit(as);
861 void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as);
865 namespace this_thread
868 void at_thread_exit(F f)
870 detail::thread_exit_function_base* const thread_exit_func=detail::heap_new<detail::thread_exit_function<F> >(f);
871 detail::add_thread_exit_function(thread_exit_func);
880 #include <boost/config/abi_suffix.hpp>