From b13eb43633905c20b8b697c6092c0971f1dea133 Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Wed, 19 Dec 2007 22:46:16 +0000 Subject: [PATCH] Merged revisions 42067-42179 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r42067 | johnmaddock | 2007-12-15 04:32:18 -0800 (Sat, 15 Dec 2007) | 1 line MSVC warning suppression. ........ r42069 | bemandawes | 2007-12-15 06:26:16 -0800 (Sat, 15 Dec 2007) | 1 line Correct misspelling of library name ........ r42074 | johnmaddock | 2007-12-15 09:10:03 -0800 (Sat, 15 Dec 2007) | 1 line Fix error messages so they work with Boost.Format. ........ r42076 | johnmaddock | 2007-12-15 09:36:31 -0800 (Sat, 15 Dec 2007) | 1 line Trivial patches to silence MSVC warnings. ........ r42078 | johnmaddock | 2007-12-15 10:29:29 -0800 (Sat, 15 Dec 2007) | 1 line Disable long double tests if there's no long double support. ........ r42080 | johnmaddock | 2007-12-15 10:49:13 -0800 (Sat, 15 Dec 2007) | 1 line Yet another MSVC warning suppression. ........ r42082 | bgubenko | 2007-12-15 10:53:01 -0800 (Sat, 15 Dec 2007) | 1 line mark up Boost.Test tests for Linux ia64 gcc; make Boost.Interprocess unsupported on Linux ia64 gcc and PA-RISC ........ r42086 | anthonyw | 2007-12-15 14:34:30 -0800 (Sat, 15 Dec 2007) | 1 line added timed_wait overloads that take a duration ........ r42087 | anthonyw | 2007-12-15 14:36:43 -0800 (Sat, 15 Dec 2007) | 1 line explicit move functions for threads, with a test ........ r42105 | andreas_huber69 | 2007-12-16 06:58:24 -0800 (Sun, 16 Dec 2007) | 1 line Removed markup for now passing Sandia tests. ........ r42112 | bemandawes | 2007-12-16 14:39:32 -0800 (Sun, 16 Dec 2007) | 1 line Add intel-win-10.0 as required ........ r42116 | djowel | 2007-12-17 01:27:42 -0800 (Mon, 17 Dec 2007) | 1 line fixed documentation bug ........ r42117 | anthonyw | 2007-12-17 03:24:13 -0800 (Mon, 17 Dec 2007) | 1 line Updated move function test to be fair to Borland ........ r42118 | anthonyw | 2007-12-17 04:52:50 -0800 (Mon, 17 Dec 2007) | 1 line boost::move support for locks ........ r42119 | chris_kohlhoff | 2007-12-17 05:04:30 -0800 (Mon, 17 Dec 2007) | 2 lines Fixes for older HP-UX. ........ r42120 | chris_kohlhoff | 2007-12-17 05:08:10 -0800 (Mon, 17 Dec 2007) | 2 lines Bump version number. ........ r42121 | chris_kohlhoff | 2007-12-17 05:17:46 -0800 (Mon, 17 Dec 2007) | 2 lines Documentation fixes. ........ r42127 | bgubenko | 2007-12-17 10:06:11 -0800 (Mon, 17 Dec 2007) | 1 line markup test library test prg_exec_fail2 for PA-RISC ........ r42138 | johnmaddock | 2007-12-18 08:37:23 -0800 (Tue, 18 Dec 2007) | 1 line Fixes #1525. ........ r42141 | marshall | 2007-12-18 10:33:55 -0800 (Tue, 18 Dec 2007) | 1 line Patches to fixe #1423 and #1473 ........ r42145 | fmhess | 2007-12-18 12:14:01 -0800 (Tue, 18 Dec 2007) | 4 lines Prevented "classname"/"methodname"/etc. elements inside "type" elements inside "static-constant" elements from getting dropped. ........ r42164 | djowel | 2007-12-19 02:33:14 -0800 (Wed, 19 Dec 2007) | 1 line bug fix for end_impl. ........ r42165 | djowel | 2007-12-19 02:33:39 -0800 (Wed, 19 Dec 2007) | 1 line bug fix for end_impl. (test) ........ r42166 | anthonyw | 2007-12-19 02:39:45 -0800 (Wed, 19 Dec 2007) | 1 line Updated thread ID, and added tests ........ r42167 | djowel | 2007-12-19 02:42:04 -0800 (Wed, 19 Dec 2007) | 1 line tweakbug fix for end_impl (tweak). ........ r42168 | anthonyw | 2007-12-19 02:45:01 -0800 (Wed, 19 Dec 2007) | 1 line Implement hardware_concurrency for pthread ........ r42169 | johnmaddock | 2007-12-19 08:41:54 -0800 (Wed, 19 Dec 2007) | 1 line Fix graph title. ........ [SVN r42185] --- include/boost/thread/detail/move.hpp | 6 - include/boost/thread/locks.hpp | 78 +++++++++- include/boost/thread/pthread/thread.hpp | 70 ++++++--- include/boost/thread/pthread/thread_data.hpp | 9 +- .../boost/thread/win32/condition_variable.hpp | 22 +++ include/boost/thread/win32/thread.hpp | 19 ++- src/pthread/thread.cpp | 33 ++-- test/Jamfile.v2 | 3 + test/test_hardware_concurrency.cpp | 21 +++ test/test_move_function.cpp | 54 +++++++ test/test_thread_id.cpp | 147 ++++++++++++++++++ 11 files changed, 419 insertions(+), 43 deletions(-) create mode 100644 test/test_hardware_concurrency.cpp create mode 100644 test/test_move_function.cpp create mode 100644 test/test_thread_id.cpp 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; +}