#ifndef BOOST_THREAD_THREAD_COMMON_HPP #define BOOST_THREAD_THREAD_COMMON_HPP // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // (C) Copyright 2007-10 Anthony Williams // (C) Copyright 20011-12 Vicente J. Botet Escriba #include #include #ifndef BOOST_NO_IOSTREAM #include #endif #include #include #include #include #include #include #include #include #include #include #include #include //#include //#include #include #include #include #include #include #include #ifdef BOOST_THREAD_USES_CHRONO #include #include #endif #include #ifdef BOOST_MSVC #pragma warning(push) #pragma warning(disable:4251) #endif namespace boost { namespace detail { template class thread_data: public detail::thread_data_base { public: BOOST_THREAD_NO_COPYABLE(thread_data) #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES thread_data(BOOST_THREAD_RV_REF(F) f_): f(boost::forward(f_)) {} // This overloading must be removed if we want the packaged_task's tests to pass. // thread_data(F& f_): // f(f_) // {} #else thread_data(BOOST_THREAD_RV_REF(F) f_): f(f_) {} thread_data(F f_): f(f_) {} #endif //thread_data() {} void run() { f(); } private: F f; }; template class thread_data >: public detail::thread_data_base { private: F& f; public: BOOST_THREAD_NO_COPYABLE(thread_data) thread_data(boost::reference_wrapper f_): f(f_) {} void run() { f(); } }; template class thread_data >: public detail::thread_data_base { private: F& f; public: BOOST_THREAD_NO_COPYABLE(thread_data) thread_data(const boost::reference_wrapper f_): f(f_) {} void run() { f(); } }; } class BOOST_THREAD_DECL thread { public: typedef thread_attributes attributes; BOOST_THREAD_MOVABLE_ONLY(thread) private: void release_handle(); detail::thread_data_ptr thread_info; void start_thread(); void start_thread(const attributes& attr); explicit thread(detail::thread_data_ptr data); detail::thread_data_ptr get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const; #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f) { return detail::thread_data_ptr(detail::heap_new::type> >( boost::forward(f))); } static inline detail::thread_data_ptr make_thread_info(void (*f)()) { return detail::thread_data_ptr(detail::heap_new >( boost::forward(f))); } #else template static inline detail::thread_data_ptr make_thread_info(F f) { return detail::thread_data_ptr(detail::heap_new >(f)); } template static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f) { return detail::thread_data_ptr(detail::heap_new >(f)); } #endif struct dummy; public: #if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. #if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) thread(const volatile thread&); #endif #endif thread() BOOST_NOEXCEPT; ~thread() { #if defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE if (joinable()) { std::terminate(); } #else detach(); #endif } #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template < class F > explicit thread(BOOST_THREAD_RV_REF(F) f , typename disable_if::type, thread>, dummy* >::type=0 ): thread_info(make_thread_info(thread_detail::decay_copy(boost::forward(f)))) { start_thread(); } template < class F > thread(attributes& attrs, BOOST_THREAD_RV_REF(F) f): thread_info(make_thread_info(thread_detail::decay_copy(boost::forward(f)))) { start_thread(attrs); } #else #ifdef BOOST_NO_SFINAE template explicit thread(F f): thread_info(make_thread_info(f)) { start_thread(); } template thread(attributes& attrs, F f): thread_info(make_thread_info(f)) { start_thread(attrs); } #else template explicit thread(F f // todo Disable also if Or is_same::type, thread> , typename disable_if, dummy* >::type=0): thread_info(make_thread_info(f)) { start_thread(); } template thread(attributes& attrs, F f , typename disable_if, dummy* >::type=0): thread_info(make_thread_info(f)) { start_thread(attrs); } #endif template explicit thread(BOOST_THREAD_RV_REF(F) f , typename disable_if::type, thread>, dummy* >::type=0 ): thread_info(make_thread_info(f)) { start_thread(); } template thread(attributes& attrs, BOOST_THREAD_RV_REF(F) f): thread_info(make_thread_info(f)) { start_thread(attrs); } #endif thread(BOOST_THREAD_RV_REF(thread) x) { thread_info=BOOST_THREAD_RV(x).thread_info; BOOST_THREAD_RV(x).thread_info.reset(); } #if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. #if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) thread& operator=(thread x) { swap(x); return *this; } #endif #endif thread& operator=(BOOST_THREAD_RV_REF(thread) other) BOOST_NOEXCEPT { #if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE if (joinable()) std::terminate(); #endif thread_info=BOOST_THREAD_RV(other).thread_info; BOOST_THREAD_RV(other).thread_info.reset(); return *this; } template thread(F f,A1 a1,typename disable_if, dummy* >::type=0): thread_info(make_thread_info(boost::bind(boost::type(),f,a1))) { start_thread(); } template thread(F f,A1 a1,A2 a2): thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2))) { start_thread(); } template thread(F f,A1 a1,A2 a2,A3 a3): thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3))) { start_thread(); } template thread(F f,A1 a1,A2 a2,A3 a3,A4 a4): thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4))) { start_thread(); } template thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5): thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5))) { start_thread(); } template thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6): thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5,a6))) { start_thread(); } template thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7): thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5,a6,a7))) { start_thread(); } template thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8): thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5,a6,a7,a8))) { start_thread(); } template thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8,A9 a9): thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5,a6,a7,a8,a9))) { start_thread(); } void swap(thread& x) BOOST_NOEXCEPT { thread_info.swap(x.thread_info); } class BOOST_SYMBOL_VISIBLE id; id get_id() const BOOST_NOEXCEPT; bool joinable() const BOOST_NOEXCEPT; void join(); #ifdef BOOST_THREAD_USES_CHRONO template bool try_join_for(const chrono::duration& rel_time) { return try_join_until(chrono::steady_clock::now() + rel_time); } template bool try_join_until(const chrono::time_point& t) { using namespace chrono; system_clock::time_point s_now = system_clock::now(); typename Clock::time_point c_now = Clock::now(); return try_join_until(s_now + ceil(t - c_now)); } template bool try_join_until(const chrono::time_point& t) { using namespace chrono; typedef time_point nano_sys_tmpt; return try_join_until(nano_sys_tmpt(ceil(t.time_since_epoch()))); } #endif #if defined(BOOST_THREAD_PLATFORM_WIN32) bool timed_join(const system_time& abs_time); private: bool do_try_join_until(uintmax_t milli); public: #ifdef BOOST_THREAD_USES_CHRONO bool try_join_until(const chrono::time_point& tp) { chrono::milliseconds rel_time= chrono::ceil(tp-chrono::system_clock::now()); return do_try_join_until(rel_time.count()); } #endif #else bool timed_join(const system_time& abs_time) { struct timespec const ts=detail::get_timespec(abs_time); return do_try_join_until(ts); } #ifdef BOOST_THREAD_USES_CHRONO bool try_join_until(const chrono::time_point& tp) { using namespace chrono; nanoseconds d = tp.time_since_epoch(); timespec ts; seconds s = duration_cast(d); ts.tv_sec = static_cast(s.count()); ts.tv_nsec = static_cast((d - s).count()); return do_try_join_until(ts); } #endif private: bool do_try_join_until(struct timespec const &timeout); public: #endif template inline bool timed_join(TimeDuration const& rel_time) { return timed_join(get_system_time()+rel_time); } void detach(); static unsigned hardware_concurrency() BOOST_NOEXCEPT; #define BOOST_THREAD_DEFINES_THREAD_NATIVE_HANDLE typedef detail::thread_data_base::native_handle_type native_handle_type; native_handle_type native_handle(); #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 // Use thread::id when comparisions are needed // backwards compatibility bool operator==(const thread& other) const; bool operator!=(const thread& other) const; #endif static inline void yield() BOOST_NOEXCEPT { this_thread::yield(); } static inline void sleep(const system_time& xt) { this_thread::sleep(xt); } // extensions void interrupt(); bool interruption_requested() const BOOST_NOEXCEPT; }; inline void swap(thread& lhs,thread& rhs) BOOST_NOEXCEPT { return lhs.swap(rhs); } #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES inline thread&& move(thread& t) BOOST_NOEXCEPT { return static_cast(t); } #endif BOOST_THREAD_DCL_MOVABLE(thread) namespace this_thread { thread::id BOOST_THREAD_DECL get_id() BOOST_NOEXCEPT; void BOOST_THREAD_DECL interruption_point(); bool BOOST_THREAD_DECL interruption_enabled() BOOST_NOEXCEPT; bool BOOST_THREAD_DECL interruption_requested() BOOST_NOEXCEPT; inline BOOST_SYMBOL_VISIBLE void sleep(xtime const& abs_time) { sleep(system_time(abs_time)); } } class BOOST_SYMBOL_VISIBLE thread::id { private: friend inline std::size_t hash_value(const thread::id &v) { #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID return hash_value(v.thread_data); #else return hash_value(v.thread_data.get()); #endif } #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID #if defined(BOOST_THREAD_PLATFORM_WIN32) typedef unsigned int data; #else typedef thread::native_handle_type data; #endif #else typedef detail::thread_data_ptr data; #endif data thread_data; id(data thread_data_): thread_data(thread_data_) {} friend class thread; friend id BOOST_THREAD_DECL this_thread::get_id() BOOST_NOEXCEPT; public: id() BOOST_NOEXCEPT: #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID #if defined(BOOST_THREAD_PLATFORM_WIN32) thread_data(0) #else thread_data(0) #endif #else thread_data() #endif {} id(const id& other) BOOST_NOEXCEPT : thread_data(other.thread_data) {} bool operator==(const id& y) const BOOST_NOEXCEPT { return thread_data==y.thread_data; } bool operator!=(const id& y) const BOOST_NOEXCEPT { return thread_data!=y.thread_data; } bool operator<(const id& y) const BOOST_NOEXCEPT { return thread_data(const id& y) const BOOST_NOEXCEPT { return y.thread_data=(const id& y) const BOOST_NOEXCEPT { return !(thread_data friend BOOST_SYMBOL_VISIBLE std::basic_ostream& operator<<(std::basic_ostream& os, const id& x) { if(x.thread_data) { io::ios_flags_saver ifs( os ); return os<< std::hex << x.thread_data; } else { return os<<"{Not-any-thread}"; } } #else template BOOST_SYMBOL_VISIBLE std::basic_ostream& print(std::basic_ostream& os) const { if(thread_data) { io::ios_flags_saver ifs( os ); return os<< std::hex << thread_data; } else { return os<<"{Not-any-thread}"; } } #endif #endif }; #if !defined(BOOST_NO_IOSTREAM) && defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template BOOST_SYMBOL_VISIBLE std::basic_ostream& operator<<(std::basic_ostream& os, const thread::id& x) { return x.print(os); } #endif #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 inline bool thread::operator==(const thread& other) const { return get_id()==other.get_id(); } inline bool thread::operator!=(const thread& other) const { return get_id()!=other.get_id(); } #endif namespace detail { struct thread_exit_function_base { virtual ~thread_exit_function_base() {} virtual void operator()()=0; }; template struct thread_exit_function: thread_exit_function_base { F f; thread_exit_function(F f_): f(f_) {} void operator()() { f(); } }; void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*); } namespace this_thread { template void at_thread_exit(F f) { detail::thread_exit_function_base* const thread_exit_func=detail::heap_new >(f); detail::add_thread_exit_function(thread_exit_func); } } } #ifdef BOOST_MSVC #pragma warning(pop) #endif #include #endif