diff --git a/include/boost/thread/detail/move.hpp b/include/boost/thread/detail/move.hpp index 4c90abc3..011ae4ea 100644 --- a/include/boost/thread/detail/move.hpp +++ b/include/boost/thread/detail/move.hpp @@ -23,12 +23,6 @@ namespace boost return &t; } }; - - template - thread_move_t thread_move(T& t) - { - return thread_move_t(t); - } } } diff --git a/include/boost/thread/locks.hpp b/include/boost/thread/locks.hpp index 999b87f8..7d9e8693 100644 --- a/include/boost/thread/locks.hpp +++ b/include/boost/thread/locks.hpp @@ -90,9 +90,20 @@ namespace boost m(other->m),is_locked(other->is_locked) { other->is_locked=false; + other->m=0; } unique_lock(detail::thread_move_t > other); + operator detail::thread_move_t >() + { + return move(); + } + + detail::thread_move_t > move() + { + return detail::thread_move_t >(*this); + } + unique_lock& operator=(detail::thread_move_t > other) { unique_lock temp(other); @@ -196,6 +207,18 @@ namespace boost friend class upgrade_lock; }; + template + inline detail::thread_move_t > move(unique_lock & x) + { + return x.move(); + } + + template + inline detail::thread_move_t > move(detail::thread_move_t > x) + { + return x; + } + template class shared_lock { @@ -254,6 +277,17 @@ namespace boost } } + operator detail::thread_move_t >() + { + return move(); + } + + detail::thread_move_t > move() + { + return detail::thread_move_t >(*this); + } + + shared_lock& operator=(detail::thread_move_t > other) { shared_lock temp(other); @@ -341,6 +375,19 @@ namespace boost }; + template + inline detail::thread_move_t > move(shared_lock & x) + { + return x.move(); + } + + template + inline detail::thread_move_t > move(detail::thread_move_t > x) + { + return x; + } + + template class upgrade_lock { @@ -380,6 +427,17 @@ namespace boost } } + operator detail::thread_move_t >() + { + return move(); + } + + detail::thread_move_t > move() + { + return detail::thread_move_t >(*this); + } + + upgrade_lock& operator=(detail::thread_move_t > other) { upgrade_lock temp(other); @@ -452,6 +510,19 @@ namespace boost friend class unique_lock; }; + + template + inline detail::thread_move_t > move(upgrade_lock & x) + { + return x.move(); + } + + template + inline detail::thread_move_t > move(detail::thread_move_t > x) + { + return x; + } + template unique_lock::unique_lock(detail::thread_move_t > other): m(other->m),is_locked(other->is_locked) @@ -474,18 +545,18 @@ namespace boost upgrade_to_unique_lock& operator=(upgrade_to_unique_lock&); public: explicit upgrade_to_unique_lock(upgrade_lock& m_): - source(&m_),exclusive(detail::thread_move(*source)) + source(&m_),exclusive(move(*source)) {} ~upgrade_to_unique_lock() { if(source) { - *source=detail::thread_move(exclusive); + *source=move(exclusive); } } upgrade_to_unique_lock(detail::thread_move_t > other): - source(other->source),exclusive(detail::thread_move(other->exclusive)) + source(other->source),exclusive(move(other->exclusive)) { other->source=0; } @@ -515,6 +586,7 @@ namespace boost return exclusive.owns_lock(); } }; + } #endif diff --git a/include/boost/thread/pthread/thread.hpp b/include/boost/thread/pthread/thread.hpp index ad497230..24437ba6 100644 --- a/include/boost/thread/pthread/thread.hpp +++ b/include/boost/thread/pthread/thread.hpp @@ -40,44 +40,62 @@ namespace boost { class thread_id { - boost::optional id; - + private: + detail::thread_data_ptr thread_data; + + thread_id(detail::thread_data_ptr thread_data_): + thread_data(thread_data_) + {} friend class boost::thread; - friend thread_id this_thread::get_id(); - - thread_id(pthread_t id_): - id(id_) - {} - public: - thread_id() + thread_id(): + thread_data() {} - + bool operator==(const thread_id& y) const { - return (id && y.id) && (pthread_equal(*id,*y.id)!=0); + return thread_data==y.thread_data; } bool operator!=(const thread_id& y) const { - return !(*this==y); + return thread_data!=y.thread_data; + } + + bool operator<(const thread_id& y) const + { + return thread_data(const thread_id& y) const + { + return y.thread_data=(const thread_id& y) const + { + return !(thread_data friend std::basic_ostream& operator<<(std::basic_ostream& os, const thread_id& x) { - if(x.id) + if(x.thread_data) { - return os<<*x.id; + return os< thread_info; + detail::thread_data_ptr thread_info; void start_thread(); - explicit thread(boost::shared_ptr data); + explicit thread(detail::thread_data_ptr data); - boost::shared_ptr get_thread_info() const; + detail::thread_data_ptr get_thread_info() const; public: thread(); @@ -169,6 +187,17 @@ namespace boost bool interruption_requested() const; }; + inline detail::thread_move_t move(thread& x) + { + return x.move(); + } + + inline detail::thread_move_t move(detail::thread_move_t x) + { + return x; + } + + template struct thread::thread_data >: detail::thread_data_base @@ -208,10 +237,7 @@ namespace boost ~restore_interruption(); }; - inline thread::id get_id() - { - return thread::id(pthread_self()); - } + BOOST_THREAD_DECL thread::id get_id(); BOOST_THREAD_DECL void interruption_point(); BOOST_THREAD_DECL bool interruption_enabled(); diff --git a/include/boost/thread/pthread/thread_data.hpp b/include/boost/thread/pthread/thread_data.hpp index f11035f1..234ba882 100644 --- a/include/boost/thread/pthread/thread_data.hpp +++ b/include/boost/thread/pthread/thread_data.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -21,10 +22,14 @@ namespace boost { struct thread_exit_callback_node; struct tss_data_node; + + struct thread_data_base; + typedef boost::shared_ptr thread_data_ptr; - struct thread_data_base + struct thread_data_base: + enable_shared_from_this { - boost::shared_ptr self; + thread_data_ptr self; pthread_t thread_handle; boost::mutex data_mutex; boost::condition_variable done_condition; diff --git a/include/boost/thread/win32/condition_variable.hpp b/include/boost/thread/win32/condition_variable.hpp index 3a29ef1c..bfd1f1ff 100644 --- a/include/boost/thread/win32/condition_variable.hpp +++ b/include/boost/thread/win32/condition_variable.hpp @@ -276,6 +276,16 @@ namespace boost return do_wait(m,wait_until); } + bool timed_wait(unique_lock& m,boost::xtime const& wait_until) + { + return do_wait(m,system_time(wait_until)); + } + template + bool timed_wait(unique_lock& m,duration_type const& wait_duration) + { + return do_wait(m,wait_duration.total_milliseconds()); + } + template bool timed_wait(unique_lock& m,boost::system_time const& wait_until,predicate_type pred) { @@ -315,6 +325,18 @@ namespace boost return do_wait(m,wait_until); } + template + bool timed_wait(lock_type& m,boost::xtime const& wait_until) + { + return do_wait(m,system_time(wait_until)); + } + + template + bool timed_wait(lock_type& m,duration_type const& wait_duration) + { + return do_wait(m,wait_duration.total_milliseconds()); + } + template bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred) { diff --git a/include/boost/thread/win32/thread.hpp b/include/boost/thread/win32/thread.hpp index 14d93f83..9ff339ec 100644 --- a/include/boost/thread/win32/thread.hpp +++ b/include/boost/thread/win32/thread.hpp @@ -245,6 +245,16 @@ namespace boost bool interruption_requested() const; }; + inline detail::thread_move_t move(thread& x) + { + return x.move(); + } + + inline detail::thread_move_t move(detail::thread_move_t x) + { + return x; + } + template struct thread::thread_data >: detail::thread_data_base @@ -354,7 +364,14 @@ namespace boost friend std::basic_ostream& operator<<(std::basic_ostream& os, const id& x) { - return os< #include #include +#ifdef __linux__ +#include +#endif #include "timeconv.inl" @@ -229,7 +232,7 @@ namespace boost return !operator==(other); } - boost::shared_ptr thread::get_thread_info() const + detail::thread_data_ptr thread::get_thread_info() const { lock_guard l(thread_info_mutex); return thread_info; @@ -237,7 +240,7 @@ namespace boost void thread::join() { - boost::shared_ptr const local_thread_info=get_thread_info(); + detail::thread_data_ptr const local_thread_info=get_thread_info(); if(local_thread_info) { bool do_join=false; @@ -281,7 +284,7 @@ namespace boost bool thread::timed_join(system_time const& wait_until) { - boost::shared_ptr const local_thread_info=get_thread_info(); + detail::thread_data_ptr const local_thread_info=get_thread_info(); if(local_thread_info) { bool do_join=false; @@ -335,7 +338,7 @@ namespace boost void thread::detach() { - boost::shared_ptr local_thread_info; + detail::thread_data_ptr local_thread_info; { lock_guard l1(thread_info_mutex); thread_info.swap(local_thread_info); @@ -408,15 +411,21 @@ namespace boost unsigned thread::hardware_concurrency() { - return 1; +#if defined(PTW32_VERSION) || defined(__hpux) + return pthread_num_processors_np(); +#elif defined(__linux__) + return get_nprocs; +#else + return 0; +#endif } thread::id thread::get_id() const { - boost::shared_ptr local_thread_info=get_thread_info(); + detail::thread_data_ptr const local_thread_info=get_thread_info(); if(local_thread_info) { - return id(local_thread_info->thread_handle); + return id(local_thread_info); } else { @@ -426,7 +435,7 @@ namespace boost void thread::interrupt() { - boost::shared_ptr local_thread_info=get_thread_info(); + detail::thread_data_ptr const local_thread_info=get_thread_info(); if(local_thread_info) { lock_guard lk(local_thread_info->data_mutex); @@ -440,7 +449,7 @@ namespace boost bool thread::interruption_requested() const { - boost::shared_ptr local_thread_info=get_thread_info(); + detail::thread_data_ptr const local_thread_info=get_thread_info(); if(local_thread_info) { lock_guard lk(local_thread_info->data_mutex); @@ -455,6 +464,12 @@ namespace boost namespace this_thread { + thread::id get_id() + { + boost::detail::thread_data_base* const thread_info=get_or_make_current_thread_data(); + return thread::id(thread_info?thread_info->shared_from_this():detail::thread_data_ptr()); + } + void interruption_point() { boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data(); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 4ff2d48f..d9e4bcb9 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -35,7 +35,10 @@ rule thread-run ( sources ) { test-suite "threads" : [ thread-run test_thread.cpp ] + [ thread-run test_thread_id.cpp ] + [ thread-run test_hardware_concurrency.cpp ] [ thread-run test_thread_move.cpp ] + [ thread-run test_move_function.cpp ] [ thread-run test_mutex.cpp ] [ thread-run test_condition_notify_one.cpp ] [ thread-run test_condition_timed_wait_times_out.cpp ] diff --git a/test/test_hardware_concurrency.cpp b/test/test_hardware_concurrency.cpp new file mode 100644 index 00000000..7c1c148b --- /dev/null +++ b/test/test_hardware_concurrency.cpp @@ -0,0 +1,21 @@ +// Copyright (C) 2007 Anthony Williams +// +// 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) +#include +#include +#include + +void test_hardware_concurrency_is_non_zero() +{ + BOOST_CHECK(boost::thread::hardware_concurrency()!=0); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: hardware concurrency test suite"); + + test->add(BOOST_TEST_CASE(test_hardware_concurrency_is_non_zero)); + return test; +} diff --git a/test/test_move_function.cpp b/test/test_move_function.cpp new file mode 100644 index 00000000..153a4cf1 --- /dev/null +++ b/test/test_move_function.cpp @@ -0,0 +1,54 @@ +// Copyright (C) 2007 Anthony Williams +// +// 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) +#include +#include +#include + +void do_nothing() +{} + +void test_thread_move_from_lvalue_on_construction() +{ + boost::thread src(do_nothing); + boost::thread::id src_id=src.get_id(); + boost::thread dest(boost::move(src)); + boost::thread::id dest_id=dest.get_id(); + BOOST_CHECK(src_id==dest_id); + BOOST_CHECK(src.get_id()==boost::thread::id()); + dest.join(); +} + +void test_thread_move_from_rvalue_on_construction() +{ + boost::thread x(boost::move(boost::thread(do_nothing))); + BOOST_CHECK(x.get_id()!=boost::thread::id()); + x.join(); +} + + +void test_unique_lock_move_from_lvalue_on_construction() +{ + boost::mutex m; + boost::unique_lock l(m); + BOOST_CHECK(l.owns_lock()); + BOOST_CHECK(l.mutex()==&m); + + boost::unique_lock l2(boost::move(l)); + BOOST_CHECK(!l.owns_lock()); + BOOST_CHECK(!l.mutex()); + BOOST_CHECK(l2.owns_lock()); + BOOST_CHECK(l2.mutex()==&m); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: thread move test suite"); + + test->add(BOOST_TEST_CASE(test_thread_move_from_lvalue_on_construction)); + test->add(BOOST_TEST_CASE(test_thread_move_from_rvalue_on_construction)); + test->add(BOOST_TEST_CASE(test_unique_lock_move_from_lvalue_on_construction)); + return test; +} diff --git a/test/test_thread_id.cpp b/test/test_thread_id.cpp new file mode 100644 index 00000000..117c78c2 --- /dev/null +++ b/test/test_thread_id.cpp @@ -0,0 +1,147 @@ +// Copyright (C) 2007 Anthony Williams +// +// 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) +#include +#include +#include + +void do_nothing() +{} + +void test_thread_id_for_default_constructed_thread_is_default_constructed_id() +{ + boost::thread t; + BOOST_CHECK(t.get_id()==boost::thread::id()); +} + +void test_thread_id_for_running_thread_is_not_default_constructed_id() +{ + boost::thread t(do_nothing); + BOOST_CHECK(t.get_id()!=boost::thread::id()); + t.join(); +} + +void test_different_threads_have_different_ids() +{ + boost::thread t(do_nothing); + boost::thread t2(do_nothing); + BOOST_CHECK(t.get_id()!=t2.get_id()); + t.join(); + t2.join(); +} + +void test_thread_ids_have_a_total_order() +{ + boost::thread t(do_nothing); + boost::thread t2(do_nothing); + boost::thread t3(do_nothing); + BOOST_CHECK(t.get_id()!=t2.get_id()); + BOOST_CHECK(t.get_id()!=t3.get_id()); + BOOST_CHECK(t2.get_id()!=t3.get_id()); + + BOOST_CHECK((t.get_id()t2.get_id()) != (t2.get_id()>t.get_id())); + BOOST_CHECK((t.get_id()>t3.get_id()) != (t3.get_id()>t.get_id())); + BOOST_CHECK((t2.get_id()>t3.get_id()) != (t3.get_id()>t2.get_id())); + + BOOST_CHECK((t.get_id()t.get_id())); + BOOST_CHECK((t2.get_id()t2.get_id())); + BOOST_CHECK((t.get_id()t.get_id())); + BOOST_CHECK((t3.get_id()t3.get_id())); + BOOST_CHECK((t2.get_id()t2.get_id())); + BOOST_CHECK((t3.get_id()t3.get_id())); + + BOOST_CHECK((t.get_id()=t.get_id())); + BOOST_CHECK((t2.get_id()=t2.get_id())); + BOOST_CHECK((t.get_id()=t.get_id())); + BOOST_CHECK((t3.get_id()=t3.get_id())); + BOOST_CHECK((t2.get_id()=t2.get_id())); + BOOST_CHECK((t3.get_id()=t3.get_id())); + + BOOST_CHECK((t.get_id()<=t2.get_id()) == (t2.get_id()>t.get_id())); + BOOST_CHECK((t2.get_id()<=t.get_id()) == (t.get_id()>t2.get_id())); + BOOST_CHECK((t.get_id()<=t3.get_id()) == (t3.get_id()>t.get_id())); + BOOST_CHECK((t3.get_id()<=t.get_id()) == (t.get_id()>t3.get_id())); + BOOST_CHECK((t2.get_id()<=t3.get_id()) == (t3.get_id()>t2.get_id())); + BOOST_CHECK((t3.get_id()<=t2.get_id()) == (t2.get_id()>t3.get_id())); + + if((t.get_id() t.get_id())); + BOOST_CHECK(!(boost::thread::id() > t2.get_id())); + BOOST_CHECK(!(boost::thread::id() > t2.get_id())); + + BOOST_CHECK(!(boost::thread::id() >= t.get_id())); + BOOST_CHECK(!(boost::thread::id() >= t2.get_id())); + BOOST_CHECK(!(boost::thread::id() >= t2.get_id())); + + t.join(); + t2.join(); + t3.join(); +} + +void get_thread_id(boost::thread::id* id) +{ + *id=boost::this_thread::get_id(); +} + +void test_thread_id_of_running_thread_returned_by_this_thread_get_id() +{ + boost::thread::id id; + boost::thread t(boost::bind(get_thread_id,&id)); + boost::thread::id t_id=t.get_id(); + t.join(); + BOOST_CHECK(id==t_id); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: thread move test suite"); + + test->add(BOOST_TEST_CASE(test_thread_id_for_default_constructed_thread_is_default_constructed_id)); + test->add(BOOST_TEST_CASE(test_thread_id_for_running_thread_is_not_default_constructed_id)); + test->add(BOOST_TEST_CASE(test_different_threads_have_different_ids)); + test->add(BOOST_TEST_CASE(test_thread_ids_have_a_total_order)); + test->add(BOOST_TEST_CASE(test_thread_id_of_running_thread_returned_by_this_thread_get_id)); + return test; +}