diff --git a/doc/thread_ref.qbk b/doc/thread_ref.qbk index 55ff306f..e9bc5150 100644 --- a/doc/thread_ref.qbk +++ b/doc/thread_ref.qbk @@ -206,6 +206,8 @@ __thread_id__ yield a total order for every non-equal thread ID. static void sleep(const system_time& xt); }; + void swap(thread& lhs,thread& rhs); + [section:default_constructor Default Constructor] thread(); @@ -451,6 +453,36 @@ implementation. If no such instance exists, `native_handle()` and `native_handle [endsect] +[section:swap Member function `swap()`] + + void swap(thread& other); + +[variablelist + +[[Effects:] [Exchanges the threads of execution associated with `*this` and `other`, so `*this` is associated with the thread of +execution associated with `other` prior to the call, and vice-versa.]] + +[[Postconditions:] [`this->get_id()` returns the same value as `other.get_id()` prior to the call. `other.get_id()` returns the same +value as `this->get_id()` prior to the call.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:non_member_swap Non-member function `swap()`] + + void swap(thread& lhs,thread& rhs); + +[variablelist + +[[Effects:] [[link thread.thread_management.thread.swap `lhs.swap(rhs)`].]] + +] + +[endsect] + [section:id Class `boost::thread::id`] diff --git a/include/boost/thread/detail/thread.hpp b/include/boost/thread/detail/thread.hpp index 1ada38f9..afa22c32 100644 --- a/include/boost/thread/detail/thread.hpp +++ b/include/boost/thread/detail/thread.hpp @@ -311,6 +311,11 @@ namespace boost bool interruption_requested() const; }; + inline void swap(thread& lhs,thread& rhs) + { + return lhs.swap(rhs); + } + #ifdef BOOST_HAS_RVALUE_REFS inline thread&& move(thread&& t) { diff --git a/include/boost/thread/pthread/mutex.hpp b/include/boost/thread/pthread/mutex.hpp index 4b33358e..128a9405 100644 --- a/include/boost/thread/pthread/mutex.hpp +++ b/include/boost/thread/pthread/mutex.hpp @@ -11,9 +11,6 @@ #include #include #include -#ifndef _WIN32 -#include -#endif #include #include "timespec.hpp" #include "pthread_mutex_scoped_lock.hpp" diff --git a/include/boost/thread/pthread/timespec.hpp b/include/boost/thread/pthread/timespec.hpp index 105030ff..d7465c1a 100644 --- a/include/boost/thread/pthread/timespec.hpp +++ b/include/boost/thread/pthread/timespec.hpp @@ -21,7 +21,7 @@ namespace boost { inline struct timespec get_timespec(boost::system_time const& abs_time) { - struct timespec timeout={0}; + struct timespec timeout={0,0}; boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0); timeout.tv_sec=time_since_epoch.total_seconds(); diff --git a/include/boost/thread/win32/condition_variable.hpp b/include/boost/thread/win32/condition_variable.hpp index b7a38665..6e676b49 100644 --- a/include/boost/thread/win32/condition_variable.hpp +++ b/include/boost/thread/win32/condition_variable.hpp @@ -23,35 +23,96 @@ namespace boost { namespace detail { + class basic_cv_list_entry; + void intrusive_ptr_add_ref(basic_cv_list_entry * p); + void intrusive_ptr_release(basic_cv_list_entry * p); + + class basic_cv_list_entry + { + private: + detail::win32::handle_manager semaphore; + detail::win32::handle_manager wake_sem; + long waiters; + bool notified; + long references; + + basic_cv_list_entry(basic_cv_list_entry&); + void operator=(basic_cv_list_entry&); + + public: + explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_): + semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)), + wake_sem(wake_sem_.duplicate()), + waiters(1),notified(false),references(0) + {} + + static bool no_waiters(boost::intrusive_ptr const& entry) + { + return !detail::interlocked_read_acquire(&entry->waiters); + } + + void add_waiter() + { + BOOST_INTERLOCKED_INCREMENT(&waiters); + } + + void remove_waiter() + { + BOOST_INTERLOCKED_DECREMENT(&waiters); + } + + void release(unsigned count_to_release) + { + notified=true; + detail::win32::ReleaseSemaphore(semaphore,count_to_release,0); + } + + void release_waiters() + { + release(detail::interlocked_read_acquire(&waiters)); + } + + bool is_notified() const + { + return notified; + } + + bool wait(timeout wait_until) + { + return this_thread::interruptible_wait(semaphore,wait_until); + } + + bool woken() + { + unsigned long const woken_result=detail::win32::WaitForSingleObject(wake_sem,0); + BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0)); + return woken_result==0; + } + + friend void intrusive_ptr_add_ref(basic_cv_list_entry * p); + friend void intrusive_ptr_release(basic_cv_list_entry * p); + }; + + inline void intrusive_ptr_add_ref(basic_cv_list_entry * p) + { + BOOST_INTERLOCKED_INCREMENT(&p->references); + } + + inline void intrusive_ptr_release(basic_cv_list_entry * p) + { + if(!BOOST_INTERLOCKED_DECREMENT(&p->references)) + { + delete p; + } + } + class basic_condition_variable { boost::mutex internal_mutex; long total_count; unsigned active_generation_count; - struct list_entry - { - detail::win32::handle_manager semaphore; - detail::win32::handle_manager wake_sem; - long waiters; - bool notified; - long references; - - list_entry(): - semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)), - wake_sem(0), - waiters(1),notified(false),references(0) - {} - - void release(unsigned count_to_release) - { - notified=true; - detail::win32::ReleaseSemaphore(semaphore,count_to_release,0); - } - }; - - friend void intrusive_ptr_add_ref(list_entry * p); - friend void intrusive_ptr_release(list_entry * p); + typedef basic_cv_list_entry list_entry; typedef boost::intrusive_ptr entry_ptr; typedef std::vector generation_list; @@ -104,16 +165,15 @@ namespace boost } detail::interlocked_write_release(&total_count,total_count+1); - if(generations.empty() || generations.back()->notified) + if(generations.empty() || generations.back()->is_notified()) { - entry_ptr new_entry(new list_entry); - new_entry->wake_sem=wake_sem.duplicate(); + entry_ptr new_entry(new list_entry(wake_sem)); generations.push_back(new_entry); return new_entry; } else { - BOOST_INTERLOCKED_INCREMENT(&generations.back()->waiters); + generations.back()->add_waiter(); return generations.back(); } } @@ -128,7 +188,7 @@ namespace boost ~entry_manager() { - BOOST_INTERLOCKED_DECREMENT(&entry->waiters); + entry->remove_waiter(); } list_entry* operator->() @@ -155,15 +215,12 @@ namespace boost bool woken=false; while(!woken) { - if(!this_thread::interruptible_wait(entry->semaphore,wait_until)) + if(!entry->wait(wait_until)) { return false; } - unsigned long const woken_result=detail::win32::WaitForSingleObject(entry->wake_sem,0); - BOOST_ASSERT(woken_result==detail::win32::timeout || woken_result==0); - - woken=(woken_result==0); + woken=entry->woken(); } return woken; } @@ -182,10 +239,6 @@ namespace boost basic_condition_variable(const basic_condition_variable& other); basic_condition_variable& operator=(const basic_condition_variable& other); - static bool no_waiters(entry_ptr const& entry) - { - return !detail::interlocked_read_acquire(&entry->waiters); - } public: basic_condition_variable(): total_count(0),active_generation_count(0),wake_sem(0) @@ -211,7 +264,7 @@ namespace boost { (*it)->release(1); } - generations.erase(std::remove_if(generations.begin(),generations.end(),no_waiters),generations.end()); + generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end()); } } @@ -229,7 +282,7 @@ namespace boost end=generations.end(); it!=end;++it) { - (*it)->release(detail::interlocked_read_acquire(&(*it)->waiters)); + (*it)->release_waiters(); } generations.clear(); wake_sem=detail::win32::handle(0); @@ -237,20 +290,6 @@ namespace boost } }; - inline void intrusive_ptr_add_ref(basic_condition_variable::list_entry * p) - { - BOOST_INTERLOCKED_INCREMENT(&p->references); - } - - inline void intrusive_ptr_release(basic_condition_variable::list_entry * p) - { - if(!BOOST_INTERLOCKED_DECREMENT(&p->references)) - { - delete p; - } - } - - } class condition_variable: diff --git a/include/boost/thread/xtime.hpp b/include/boost/thread/xtime.hpp index 54f91720..7cc6272d 100644 --- a/include/boost/thread/xtime.hpp +++ b/include/boost/thread/xtime.hpp @@ -58,7 +58,7 @@ struct xtime inline xtime get_xtime(boost::system_time const& abs_time) { - xtime res={0}; + xtime res; boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0); res.sec=static_cast(time_since_epoch.total_seconds()); diff --git a/test/test_thread.cpp b/test/test_thread.cpp index 5535deb0..480e258a 100644 --- a/test/test_thread.cpp +++ b/test/test_thread.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2001-2003 // William E. Kempf +// Copyright (C) 2008 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) @@ -198,6 +199,22 @@ void test_timed_join() timed_test(&do_test_timed_join, 10); } +void test_swap() +{ + boost::thread t(simple_thread); + boost::thread t2(simple_thread); + boost::thread::id id1=t.get_id(); + boost::thread::id id2=t2.get_id(); + + t.swap(t2); + BOOST_CHECK(t.get_id()==id2); + BOOST_CHECK(t2.get_id()==id1); + + swap(t,t2); + BOOST_CHECK(t.get_id()==id1); + BOOST_CHECK(t2.get_id()==id2); +} + boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { @@ -211,6 +228,7 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) test->add(BOOST_TEST_CASE(test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point)); test->add(BOOST_TEST_CASE(test_creation_through_reference_wrapper)); test->add(BOOST_TEST_CASE(test_timed_join)); + test->add(BOOST_TEST_CASE(test_swap)); return test; }