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_):
159 class BOOST_THREAD_DECL thread
162 typedef thread_attributes attributes;
164 BOOST_THREAD_MOVABLE_ONLY(thread)
169 void release_handle();
171 detail::thread_data_ptr thread_info;
174 bool start_thread_noexcept();
175 bool start_thread_noexcept(const attributes& attr);
178 if (!start_thread_noexcept())
180 boost::throw_exception(thread_resource_error());
183 void start_thread(const attributes& attr)
185 if (!start_thread_noexcept(attr))
187 boost::throw_exception(thread_resource_error());
191 explicit thread(detail::thread_data_ptr data);
193 detail::thread_data_ptr get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const;
195 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
196 #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
197 template<typename F, class ...ArgTypes>
198 static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_RV_REF(ArgTypes)... args)
200 return detail::thread_data_ptr(detail::heap_new<
201 detail::thread_data<typename boost::remove_reference<F>::type, ArgTypes...>
203 boost::forward<F>(f), boost::forward<ArgTypes>(args)...
209 static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f)
211 return detail::thread_data_ptr(detail::heap_new<detail::thread_data<typename boost::remove_reference<F>::type> >(
212 boost::forward<F>(f)));
215 static inline detail::thread_data_ptr make_thread_info(void (*f)())
217 return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >(
218 boost::forward<void(*)()>(f)));
222 static inline detail::thread_data_ptr make_thread_info(F f
223 , typename disable_if_c<
224 //boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F)>::value ||
225 is_same<typename decay<F>::type, thread>::value,
229 return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
232 static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f)
234 return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
239 #if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF.
240 #if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
241 thread(const volatile thread&);
244 thread() BOOST_NOEXCEPT;
248 #if defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
256 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
260 explicit thread(BOOST_THREAD_RV_REF(F) f
261 //, typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0
263 thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f))))
270 thread(attributes const& attrs, BOOST_THREAD_RV_REF(F) f):
271 thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f))))
277 #ifdef BOOST_NO_SFINAE
279 explicit thread(F f):
280 thread_info(make_thread_info(f))
285 thread(attributes const& attrs, F f):
286 thread_info(make_thread_info(f))
293 , typename disable_if_c<
294 boost::thread_detail::is_rv<F>::value // todo ass a thread_detail::is_rv
295 //boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F)>::value
296 //|| is_same<typename decay<F>::type, thread>::value
299 thread_info(make_thread_info(f))
304 thread(attributes const& attrs, F f
305 , typename disable_if<boost::thread_detail::is_rv<F>, dummy* >::type=0
306 //, typename disable_if<boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0
308 thread_info(make_thread_info(f))
314 explicit thread(BOOST_THREAD_RV_REF(F) f
315 , typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0
317 #ifdef BOOST_THREAD_USES_MOVE
318 thread_info(make_thread_info(boost::move<F>(f))) // todo : Add forward
320 thread_info(make_thread_info(f)) // todo : Add forward
327 thread(attributes const& attrs, BOOST_THREAD_RV_REF(F) f):
328 #ifdef BOOST_THREAD_USES_MOVE
329 thread_info(make_thread_info(boost::move<F>(f))) // todo : Add forward
331 thread_info(make_thread_info(f)) // todo : Add forward
337 thread(BOOST_THREAD_RV_REF(thread) x) BOOST_NOEXCEPT
339 thread_info=BOOST_THREAD_RV(x).thread_info;
340 BOOST_THREAD_RV(x).thread_info.reset();
342 #if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF.
343 #if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
344 thread& operator=(thread x)
352 thread& operator=(BOOST_THREAD_RV_REF(thread) other) BOOST_NOEXCEPT
355 #if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
356 if (joinable()) std::terminate();
360 thread_info=BOOST_THREAD_RV(other).thread_info;
361 BOOST_THREAD_RV(other).thread_info.reset();
365 #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
366 template <class F, class Arg, class ...Args>
367 thread(F&& f, Arg&& arg, Args&&... args) :
368 thread_info(make_thread_info(
369 thread_detail::decay_copy(boost::forward<F>(f)),
370 thread_detail::decay_copy(boost::forward<Arg>(arg)),
371 thread_detail::decay_copy(boost::forward<Args>(args))...)
377 template <class F, class Arg, class ...Args>
378 thread(attributes const& attrs, F&& f, Arg&& arg, Args&&... args) :
379 thread_info(make_thread_info(
380 thread_detail::decay_copy(boost::forward<F>(f)),
381 thread_detail::decay_copy(boost::forward<Arg>(arg)),
382 thread_detail::decay_copy(boost::forward<Args>(args))...)
389 template <class F,class A1>
390 thread(F f,A1 a1,typename disable_if<boost::thread_detail::is_convertible<F&,thread_attributes >, dummy* >::type=0):
391 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1)))
395 template <class F,class A1,class A2>
396 thread(F f,A1 a1,A2 a2):
397 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2)))
402 template <class F,class A1,class A2,class A3>
403 thread(F f,A1 a1,A2 a2,A3 a3):
404 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3)))
409 template <class F,class A1,class A2,class A3,class A4>
410 thread(F f,A1 a1,A2 a2,A3 a3,A4 a4):
411 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4)))
416 template <class F,class A1,class A2,class A3,class A4,class A5>
417 thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5):
418 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5)))
423 template <class F,class A1,class A2,class A3,class A4,class A5,class A6>
424 thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6):
425 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6)))
430 template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7>
431 thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7):
432 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7)))
437 template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8>
438 thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8):
439 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8)))
444 template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8,class A9>
445 thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8,A9 a9):
446 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8,a9)))
451 void swap(thread& x) BOOST_NOEXCEPT
453 thread_info.swap(x.thread_info);
457 #ifdef BOOST_THREAD_PLATFORM_PTHREAD
458 inline id get_id() const BOOST_NOEXCEPT;
460 id get_id() const BOOST_NOEXCEPT;
464 bool joinable() const BOOST_NOEXCEPT;
466 bool join_noexcept();
470 #ifdef BOOST_THREAD_USES_CHRONO
471 #if defined(BOOST_THREAD_PLATFORM_WIN32)
472 template <class Rep, class Period>
473 bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
475 chrono::milliseconds rel_time2= chrono::ceil<chrono::milliseconds>(rel_time);
476 return do_try_join_until(rel_time2.count());
479 template <class Rep, class Period>
480 bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
482 return try_join_until(chrono::steady_clock::now() + rel_time);
485 template <class Clock, class Duration>
486 bool try_join_until(const chrono::time_point<Clock, Duration>& t)
488 using namespace chrono;
491 system_clock::time_point s_now = system_clock::now();
492 typename Clock::duration d = ceil<nanoseconds>(t-Clock::now());
493 if (d <= Clock::duration::zero()) return false; // in case the Clock::time_point t is already reached
494 joined = try_join_until(s_now + d);
498 template <class Duration>
499 bool try_join_until(const chrono::time_point<chrono::system_clock, Duration>& t)
501 using namespace chrono;
502 typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
503 return try_join_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
506 #if defined(BOOST_THREAD_PLATFORM_WIN32)
508 bool do_try_join_until_noexcept(uintmax_t milli, bool& res);
509 inline bool do_try_join_until(uintmax_t milli);
511 bool timed_join(const system_time& abs_time);
513 // return do_try_join_until(get_milliseconds_until(wait_until));
516 #ifdef BOOST_THREAD_USES_CHRONO
517 bool try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
519 chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
520 return do_try_join_until(rel_time.count());
527 bool do_try_join_until_noexcept(struct timespec const &timeout, bool& res);
528 inline bool do_try_join_until(struct timespec const &timeout);
530 #if defined BOOST_THREAD_USES_DATETIME
531 bool timed_join(const system_time& abs_time)
533 struct timespec const ts=detail::to_timespec(abs_time);
534 return do_try_join_until(ts);
537 #ifdef BOOST_THREAD_USES_CHRONO
538 bool try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
540 using namespace chrono;
541 nanoseconds d = tp.time_since_epoch();
542 timespec ts = boost::detail::to_timespec(d);
543 return do_try_join_until(ts);
550 #if defined BOOST_THREAD_USES_DATETIME
551 template<typename TimeDuration>
552 inline bool timed_join(TimeDuration const& rel_time)
554 return timed_join(get_system_time()+rel_time);
559 static unsigned hardware_concurrency() BOOST_NOEXCEPT;
560 static unsigned physical_concurrency() BOOST_NOEXCEPT;
562 #define BOOST_THREAD_DEFINES_THREAD_NATIVE_HANDLE
563 typedef detail::thread_data_base::native_handle_type native_handle_type;
564 native_handle_type native_handle();
566 #if defined BOOST_THREAD_PROVIDES_THREAD_EQ
567 // Use thread::id when comparisions are needed
568 // backwards compatibility
569 bool operator==(const thread& other) const;
570 bool operator!=(const thread& other) const;
572 #if defined BOOST_THREAD_USES_DATETIME
573 static inline void yield() BOOST_NOEXCEPT
575 this_thread::yield();
578 static inline void sleep(const system_time& xt)
580 this_thread::sleep(xt);
584 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
587 bool interruption_requested() const BOOST_NOEXCEPT;
591 inline void swap(thread& lhs,thread& rhs) BOOST_NOEXCEPT
593 return lhs.swap(rhs);
596 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
597 inline thread&& move(thread& t) BOOST_NOEXCEPT
599 return static_cast<thread&&>(t);
603 BOOST_THREAD_DCL_MOVABLE(thread)
605 namespace this_thread
607 #ifdef BOOST_THREAD_PLATFORM_PTHREAD
608 inline thread::id get_id() BOOST_NOEXCEPT;
610 thread::id BOOST_THREAD_DECL get_id() BOOST_NOEXCEPT;
613 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
614 void BOOST_THREAD_DECL interruption_point();
615 bool BOOST_THREAD_DECL interruption_enabled() BOOST_NOEXCEPT;
616 bool BOOST_THREAD_DECL interruption_requested() BOOST_NOEXCEPT;
619 #if defined BOOST_THREAD_USES_DATETIME
620 inline BOOST_SYMBOL_VISIBLE void sleep(xtime const& abs_time)
622 sleep(system_time(abs_time));
627 class BOOST_SYMBOL_VISIBLE thread::id
632 hash_value(const thread::id &v)
634 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
635 return hash_value(v.thread_data);
637 return hash_value(v.thread_data.get());
641 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
642 #if defined(BOOST_THREAD_PLATFORM_WIN32)
643 typedef unsigned int data;
645 typedef thread::native_handle_type data;
648 typedef detail::thread_data_ptr data;
652 id(data thread_data_):
653 thread_data(thread_data_)
656 friend id BOOST_THREAD_DECL this_thread::get_id() BOOST_NOEXCEPT;
659 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
666 id(const id& other) BOOST_NOEXCEPT :
667 thread_data(other.thread_data)
670 bool operator==(const id& y) const BOOST_NOEXCEPT
672 return thread_data==y.thread_data;
675 bool operator!=(const id& y) const BOOST_NOEXCEPT
677 return thread_data!=y.thread_data;
680 bool operator<(const id& y) const BOOST_NOEXCEPT
682 return thread_data<y.thread_data;
685 bool operator>(const id& y) const BOOST_NOEXCEPT
687 return y.thread_data<thread_data;
690 bool operator<=(const id& y) const BOOST_NOEXCEPT
692 return !(y.thread_data<thread_data);
695 bool operator>=(const id& y) const BOOST_NOEXCEPT
697 return !(thread_data<y.thread_data);
700 #ifndef BOOST_NO_IOSTREAM
701 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
702 template<class charT, class traits>
703 friend BOOST_SYMBOL_VISIBLE
704 std::basic_ostream<charT, traits>&
705 operator<<(std::basic_ostream<charT, traits>& os, const id& x)
709 io::ios_flags_saver ifs( os );
710 return os<< std::hex << x.thread_data;
714 return os<<"{Not-any-thread}";
718 template<class charT, class traits>
720 std::basic_ostream<charT, traits>&
721 print(std::basic_ostream<charT, traits>& os) const
725 io::ios_flags_saver ifs( os );
726 return os<< std::hex << thread_data;
730 return os<<"{Not-any-thread}";
738 #ifdef BOOST_THREAD_PLATFORM_PTHREAD
739 thread::id thread::get_id() const BOOST_NOEXCEPT
741 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
742 return const_cast<thread*>(this)->native_handle();
744 detail::thread_data_ptr const local_thread_info=(get_thread_info)();
745 return (local_thread_info? id(local_thread_info) : id());
749 namespace this_thread
751 inline thread::id get_id() BOOST_NOEXCEPT
753 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
754 return pthread_self();
756 boost::detail::thread_data_base* const thread_info=get_or_make_current_thread_data();
757 return (thread_info?thread::id(thread_info->shared_from_this()):thread::id());
762 void thread::join() {
763 if (this_thread::get_id() == get_id())
764 boost::throw_exception(thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself"));
766 BOOST_THREAD_VERIFY_PRECONDITION( join_noexcept(),
767 thread_resource_error(static_cast<int>(system::errc::invalid_argument), "boost thread: thread not joinable")
771 #ifdef BOOST_THREAD_PLATFORM_PTHREAD
772 bool thread::do_try_join_until(struct timespec const &timeout)
774 bool thread::do_try_join_until(uintmax_t timeout)
777 if (this_thread::get_id() == get_id())
778 boost::throw_exception(thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself"));
780 if (do_try_join_until_noexcept(timeout, res))
786 BOOST_THREAD_THROW_ELSE_RETURN(
787 (thread_resource_error(static_cast<int>(system::errc::invalid_argument), "boost thread: thread not joinable")),
793 #if !defined(BOOST_NO_IOSTREAM) && defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
794 template<class charT, class traits>
796 std::basic_ostream<charT, traits>&
797 operator<<(std::basic_ostream<charT, traits>& os, const thread::id& x)
803 #if defined BOOST_THREAD_PROVIDES_THREAD_EQ
804 inline bool thread::operator==(const thread& other) const
806 return get_id()==other.get_id();
809 inline bool thread::operator!=(const thread& other) const
811 return get_id()!=other.get_id();
817 struct thread_exit_function_base
819 virtual ~thread_exit_function_base()
821 virtual void operator()()=0;
825 struct thread_exit_function:
826 thread_exit_function_base
830 thread_exit_function(F f_):
840 void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*);
841 struct shared_state_base;
842 #if defined(BOOST_THREAD_PLATFORM_WIN32)
843 inline void make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
845 detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
846 if(current_thread_data)
848 current_thread_data->make_ready_at_thread_exit(as);
852 void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as);
856 namespace this_thread
859 void at_thread_exit(F f)
861 detail::thread_exit_function_base* const thread_exit_func=detail::heap_new<detail::thread_exit_function<F> >(f);
862 detail::add_thread_exit_function(thread_exit_func);
871 #include <boost/config/abi_suffix.hpp>