diff --git a/doc/changes.qbk b/doc/changes.qbk index 030dbc3a..62a6630f 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -44,7 +44,14 @@ functions. but did not lock it on construction. This facility has now been replaced with the constructor that takes a `boost::defer_lock_type` as the second parameter: ``boost::mutex::scoped_lock some_lock(some_mutex,boost::defer_lock);`` +* The `locked()` member function of the `scoped_lock` types has been renamed to __owns_lock_ref__. + +* You can no longer obtain a __thread__ instance representing the current thread: a default-constructed __thread__ object is not +associated with any thread. The only use for such a thread object was to support the comparison operators: this functionality has +been moved to __thread_id__. + * The broken `boost::read_write_mutex` has been replaced with __shared_mutex__. +* __mutex__ is now never recursive. For Boost releases prior to 1.35 __mutex__ was recursive on Windows and not on POSIX platforms. [endsect] diff --git a/doc/mutex_concepts.qbk b/doc/mutex_concepts.qbk index f99acd18..2fc5cb97 100644 --- a/doc/mutex_concepts.qbk +++ b/doc/mutex_concepts.qbk @@ -373,6 +373,7 @@ object passed to the constructor.]] class unique_lock { public: + unique_lock(); explicit unique_lock(Lockable& m_); unique_lock(Lockable& m_,adopt_lock_t); unique_lock(Lockable& m_,defer_lock_t); @@ -426,6 +427,20 @@ The member functions of __unique_lock__ are not thread-safe. In particular, __un __lockable_concept_type__ object by a particular thread, and the member functions that release ownership of the lock state (including the destructor) must be called by the same thread that acquired ownership of the lock state. +[section:defaultconstructor `unique_lock()`] + +[variablelist + +[[Effects:] [Creates a lock object with no associated mutex.]] + +[[Postcondition:] [__owns_lock_ref__ returns `false`. __mutex_func_ref__ returns `NULL`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + [section:constructor `unique_lock(Lockable & m)`] [variablelist @@ -599,6 +614,7 @@ __owns_lock_ref__ returns `false`.]] class shared_lock { public: + shared_lock(); explicit shared_lock(Lockable& m_); shared_lock(Lockable& m_,adopt_lock_t); shared_lock(Lockable& m_,defer_lock_t); @@ -644,6 +660,20 @@ The member functions of __shared_lock__ are not thread-safe. In particular, __sh ownership of a __lockable_concept_type__ object by a particular thread, and the member functions that release ownership of the lock state (including the destructor) must be called by the same thread that acquired ownership of the lock state. +[section:defaultconstructor `shared_lock()`] + +[variablelist + +[[Effects:] [Creates a lock object with no associated mutex.]] + +[[Postcondition:] [__owns_lock_ref__ returns `false`. __mutex_func_ref__ returns `NULL`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + [section:constructor `shared_lock(Lockable & m)`] [variablelist diff --git a/doc/mutexes.qbk b/doc/mutexes.qbk index 020f767f..cf920235 100644 --- a/doc/mutexes.qbk +++ b/doc/mutexes.qbk @@ -12,6 +12,9 @@ void lock(); bool try_lock(); void unlock(); + + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); typedef unique_lock scoped_lock; typedef scoped_lock scoped_try_lock; @@ -20,6 +23,23 @@ __mutex__ implements the __lockable_concept__ to provide an exclusive-ownership mutex. At most one thread can own the lock on a given instance of __mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__ and __unlock_ref__ shall be permitted. +[section:nativehandle Member function `native_handle()`] + + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); + +[variablelist + +[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying +implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + + [endsect] [section:try_mutex Typedef `try_mutex`] @@ -47,6 +67,9 @@ __try_mutex__ is a `typedef` to __mutex__, provided for backwards compatibility template bool timed_lock(TimeDuration const & relative_time); + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); + typedef unique_lock scoped_timed_lock; typedef scoped_timed_lock scoped_try_lock; typedef scoped_timed_lock scoped_lock; @@ -56,6 +79,22 @@ __timed_mutex__ implements the __timed_lockable_concept__ to provide an exclusiv lock on a given instance of __timed_mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__, __timed_lock_ref__, __timed_lock_duration_ref__ and __unlock_ref__ shall be permitted. +[section:nativehandle Member function `native_handle()`] + + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); + +[variablelist + +[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying +implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + [endsect] [section:recursive_mutex Class `recursive_mutex`] @@ -70,6 +109,9 @@ __timed_lock_ref__, __timed_lock_duration_ref__ and __unlock_ref__ shall be perm void lock(); bool try_lock(); void unlock(); + + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); typedef unique_lock scoped_lock; typedef scoped_lock scoped_try_lock; @@ -81,6 +123,22 @@ __unlock_ref__ shall be permitted. A thread that already has exclusive ownership __lock_ref__ or __try_lock_ref__ to acquire an additional level of ownership of the mutex. __unlock_ref__ must be called once for each level of ownership acquired by a single thread before ownership can be acquired by another thread. +[section:nativehandle Member function `native_handle()`] + + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); + +[variablelist + +[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying +implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + [endsect] [section:recursive_try_mutex Typedef `recursive_try_mutex`] @@ -108,6 +166,9 @@ __recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for back template bool timed_lock(TimeDuration const & relative_time); + + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); typedef unique_lock scoped_lock; typedef scoped_lock scoped_try_lock; @@ -121,6 +182,22 @@ exclusive ownership of a given __recursive_timed_mutex__ instance can call __loc __timed_lock_duration_ref__ or __try_lock_ref__ to acquire an additional level of ownership of the mutex. __unlock_ref__ must be called once for each level of ownership acquired by a single thread before ownership can be acquired by another thread. +[section:nativehandle Member function `native_handle()`] + + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); + +[variablelist + +[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying +implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + [endsect] [include shared_mutex_ref.qbk] diff --git a/doc/thread.qbk b/doc/thread.qbk index aaf975fd..b2ea6e6b 100644 --- a/doc/thread.qbk +++ b/doc/thread.qbk @@ -147,4 +147,6 @@ [include tss.qbk] +[include time.qbk] + [include acknowledgements.qbk] diff --git a/doc/thread_ref.qbk b/doc/thread_ref.qbk index caadc362..e9bc5150 100644 --- a/doc/thread_ref.qbk +++ b/doc/thread_ref.qbk @@ -17,6 +17,13 @@ allows the details of thread creation to be wrapped in a function. some_thread.join(); } +[Note: On compilers that support rvalue references, __thread__ provides a proper move constructor and move-assignment operator, and +therefore meets the C++0x ['MoveConstructible] and ['MoveAssignable] concepts. With such compilers, __thread__ can therefore be used +with containers that support those concepts. + +For other compilers, move support is provided with a move emulation layer, so containers must explicitly detect that move emulation +layer. See for details.] + [heading Launching threads] A new thread is launched by passing an object of a callable type that can be invoked with no parameters to the constructor. The @@ -43,11 +50,21 @@ __boost_thread__ must ensure that the referred-to object outlives the newly-crea // this leads to undefined behaviour If you wish to construct an instance of __thread__ with a function or callable object that requires arguments to be supplied, -this can be done using `boost::bind`: +this can be done by passing additional arguments to the __thread__ constructor: void find_the_question(int the_answer); - boost::thread deep_thought_2(boost::bind(find_the_question,42)); + boost::thread deep_thought_2(find_the_question,42); + +The arguments are ['copied] into the internal thread structure: if a reference is required, use `boost::ref`, just as for references +to callable functions. + +There is an unspecified limit on the number of additional arguments that can be passed. + +[heading Exceptions in thread functions] + +If the function or callable object passed to the __thread__ constructor propagates an exception when invoked that is not of type +__thread_interrupted__, `std::terminate()` is called. [heading Joining and detaching] @@ -189,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(); @@ -212,7 +231,9 @@ __thread_id__ yield a total order for every non-equal thread ID. [[Preconditions:] [`Callable` must by copyable.]] -[[Effects:] [`func` is copied into storage managed internally by the thread library, and that copy is invoked on a newly-created thread of execution.]] +[[Effects:] [`func` is copied into storage managed internally by the thread library, and that copy is invoked on a newly-created +thread of execution. If this invocation results in an exception being propagated into the internals of the thread library that is +not of type __thread_interrupted__, then `std::terminate()` will be called.]] [[Postconditions:] [`*this` refers to the newly created thread of execution.]] @@ -306,7 +327,7 @@ unchanged.]] [variablelist -[[Effects:] [If `*this` refers to a thread of execution, that thread of execution becomes detached, and longer has an associated __thread__ object.]] +[[Effects:] [If `*this` refers to a thread of execution, that thread of execution becomes detached, and no longer has an associated __thread__ object.]] [[Postconditions:] [`*this` no longer refers to any thread of execution.]] @@ -364,6 +385,22 @@ or 0 if this information is not available.]] [endsect] +[section:nativehandle Member function `native_handle()`] + + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); + +[variablelist + +[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying +implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + [section:equals `operator==`] bool operator==(const thread& other) const; @@ -416,6 +453,36 @@ or 0 if this information is not available.]] [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`] @@ -471,7 +538,7 @@ otherwise.]] [variablelist -[[Returns:] [`true` if `*this` and `y` represent the different threads of execution, or one represents a thread of execution, and +[[Returns:] [`true` if `*this` and `y` represent different threads of execution, or one represents a thread of execution, and the other represent __not_a_thread__, `false` otherwise.]] [[Throws:] [Nothing]] diff --git a/doc/time.qbk b/doc/time.qbk new file mode 100644 index 00000000..f817206c --- /dev/null +++ b/doc/time.qbk @@ -0,0 +1,64 @@ +[section:time Date and Time Requirements] + +As of Boost 1.35.0, the __boost_thread__ library uses the [link date_time Boost.Date_Time] library for all operations that require a +time out. These include (but are not limited to): + +* __sleep__ +* __timed_join__ +* __cond_timed_wait__ +* __timed_lock_ref__ + +For the overloads that accept an absolute time parameter, an object of type [link thread.time.system_time `boost::system_time`] is +required. Typically, this will be obtained by adding a duration to the current time, obtained with a call to [link +thread.time.get_system_time `boost::get_system_time()`]. e.g. + + boost::system_time const timeout=boost::get_system_time() + boost::posix_time::milliseconds(500); + + extern bool done; + extern boost::mutex m; + extern boost::condition_variable cond; + + boost::unique_lock lk(m); + while(!done) + { + if(!cond.timed_wait(lk,timeout)) + { + throw "timed out"; + } + } + +For the overloads that accept a ['TimeDuration] parameter, an object of any type that meets the [link +date_time.posix_time.time_duration Boost.Date_Time Time Duration requirements] can be used, e.g. + + boost::this_thread::sleep(boost::posix_time::milliseconds(25)); + + boost::mutex m; + if(m.timed_lock(boost::posix_time::nanoseconds(100))) + { + // ... + } + +[section:system_time Typedef `system_time`] + + typedef boost::posix_time::ptime system_time; + +See the documentation for [link date_time.posix_time.ptime_class `boost::posix_time::ptime`] in the Boost.Date_Time library. + +[endsect] + +[section:get_system_time Non-member function `get_system_time()`] + + system_time get_system_time(); + +[variablelist + +[[Returns:] [The current time.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + + +[endsect] \ No newline at end of file diff --git a/example/condition.cpp b/example/condition.cpp index ee2136b2..096c35d8 100644 --- a/example/condition.cpp +++ b/example/condition.cpp @@ -46,11 +46,16 @@ private: bounded_buffer buf(2); +boost::mutex io_mutex; + void sender() { int n = 0; while (n < 100) { buf.send(n); - std::cout << "sent: " << n << std::endl; + { + boost::mutex::scoped_lock io_lock(io_mutex); + std::cout << "sent: " << n << std::endl; + } ++n; } buf.send(-1); @@ -60,7 +65,10 @@ void receiver() { int n; do { n = buf.receive(); - std::cout << "received: " << n << std::endl; + { + boost::mutex::scoped_lock io_lock(io_mutex); + std::cout << "received: " << n << std::endl; + } } while (n != -1); // -1 indicates end of buffer } diff --git a/include/boost/thread.hpp b/include/boost/thread.hpp index 625e69ec..f0a39c3b 100644 --- a/include/boost/thread.hpp +++ b/include/boost/thread.hpp @@ -1,5 +1,6 @@ // Copyright (C) 2001-2003 // William E. Kempf +// (C) Copyright 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) @@ -10,12 +11,15 @@ #define BOOST_THREAD_WEK01082003_HPP #include -#include +#include #include #include #include #include #include -#include +#include +#include +#include +#include #endif diff --git a/include/boost/thread/barrier.hpp b/include/boost/thread/barrier.hpp index 665e3b03..546f5e97 100644 --- a/include/boost/thread/barrier.hpp +++ b/include/boost/thread/barrier.hpp @@ -1,6 +1,6 @@ // Copyright (C) 2002-2003 // David Moore, William E. Kempf -// Copyright (C) 2007 Anthony Williams +// Copyright (C) 2007-8 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) @@ -15,6 +15,8 @@ #include #include +#include + namespace boost { @@ -56,4 +58,6 @@ namespace boost } // namespace boost +#include + #endif diff --git a/include/boost/thread/detail/move.hpp b/include/boost/thread/detail/move.hpp index 99beb5bb..f8917758 100644 --- a/include/boost/thread/detail/move.hpp +++ b/include/boost/thread/detail/move.hpp @@ -1,11 +1,16 @@ // 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 Anthony Williams +// (C) Copyright 2007-8 Anthony Williams #ifndef BOOST_THREAD_MOVE_HPP #define BOOST_THREAD_MOVE_HPP +#include +#include + +#include + namespace boost { namespace detail @@ -14,10 +19,15 @@ namespace boost struct thread_move_t { T& t; - thread_move_t(T& t_): + explicit thread_move_t(T& t_): t(t_) {} + T& operator*() const + { + return t; + } + T* operator->() const { return &t; @@ -26,8 +36,21 @@ namespace boost void operator=(thread_move_t&); }; } + + template + typename enable_if >, detail::thread_move_t >::type move(T& t) + { + return t; + } + + template + detail::thread_move_t move(detail::thread_move_t t) + { + return t; + } } +#include #endif diff --git a/include/boost/thread/win32/thread.hpp b/include/boost/thread/detail/thread.hpp similarity index 54% rename from include/boost/thread/win32/thread.hpp rename to include/boost/thread/detail/thread.hpp index 26a9b2da..09788b20 100644 --- a/include/boost/thread/win32/thread.hpp +++ b/include/boost/thread/detail/thread.hpp @@ -1,27 +1,29 @@ -#ifndef BOOST_THREAD_THREAD_WIN32_HPP -#define BOOST_THREAD_THREAD_WIN32_HPP +#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 Anthony Williams - -#include +// (C) Copyright 2007-8 Anthony Williams + #include #include #include -#include #include -#include -#include "thread_primitives.hpp" -#include "thread_heap_alloc.hpp" +#include +#include #include #include #include #include #include #include +#include #include #include +#include +#include + +#include #ifdef BOOST_MSVC #pragma warning(push) @@ -30,195 +32,253 @@ namespace boost { - class thread_interrupted - {}; - namespace detail { - struct thread_exit_callback_node; - struct tss_data_node; - - struct thread_data_base - { - long count; - detail::win32::handle_manager thread_handle; - detail::win32::handle_manager interruption_handle; - boost::detail::thread_exit_callback_node* thread_exit_callbacks; - boost::detail::tss_data_node* tss_data; - bool interruption_enabled; - unsigned id; - - thread_data_base(): - count(0),thread_handle(detail::win32::invalid_handle_value), - interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)), - thread_exit_callbacks(0),tss_data(0), - interruption_enabled(true), - id(0) - {} - virtual ~thread_data_base() - {} - - friend void intrusive_ptr_add_ref(thread_data_base * p) - { - BOOST_INTERLOCKED_INCREMENT(&p->count); - } - - friend void intrusive_ptr_release(thread_data_base * p) - { - if(!BOOST_INTERLOCKED_DECREMENT(&p->count)) - { - detail::heap_delete(p); - } - } - - void interrupt() - { - BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0); - } - - - virtual void run()=0; - }; - - typedef boost::intrusive_ptr thread_data_ptr; - - struct timeout - { - unsigned long start; - uintmax_t milliseconds; - bool relative; - boost::system_time abs_time; - - static unsigned long const max_non_infinite_wait=0xfffffffe; - - timeout(uintmax_t milliseconds_): - start(win32::GetTickCount()), - milliseconds(milliseconds_), - relative(true), - abs_time(boost::get_system_time()) - {} - - timeout(boost::system_time const& abs_time_): - start(win32::GetTickCount()), - milliseconds(0), - relative(false), - abs_time(abs_time_) - {} - - struct remaining_time - { - bool more; - unsigned long milliseconds; - - remaining_time(uintmax_t remaining): - more(remaining>max_non_infinite_wait), - milliseconds(more?max_non_infinite_wait:(unsigned long)remaining) - {} - }; - - remaining_time remaining_milliseconds() const - { - if(is_sentinel()) - { - return remaining_time(win32::infinite); - } - else if(relative) - { - unsigned long const now=win32::GetTickCount(); - unsigned long const elapsed=now-start; - return remaining_time((elapsed - struct thread_data: - detail::thread_data_base + class thread_data: + public detail::thread_data_base { - F f; - + public: +#ifdef BOOST_HAS_RVALUE_REFS + thread_data(F&& f_): + f(static_cast(f_)) + {} +#else thread_data(F f_): f(f_) {} thread_data(detail::thread_move_t f_): f(f_) {} +#endif + void run() + { + f(); + } + private: + F f; + + void operator=(thread_data&); + thread_data(thread_data&); + }; + + template + class thread_data >: + public detail::thread_data_base + { + private: + F& f; + + void operator=(thread_data&); + thread_data(thread_data&); + public: + thread_data(boost::reference_wrapper f_): + f(f_) + {} void run() { f(); } }; + + template + class thread_data >: + public detail::thread_data_base + { + private: + F& f; + void operator=(thread_data&); + thread_data(thread_data&); + public: + thread_data(const boost::reference_wrapper f_): + f(f_) + {} + + void run() + { + f(); + } + }; + } + + class BOOST_THREAD_DECL thread + { + private: + thread(thread&); + thread& operator=(thread&); + + void release_handle(); mutable boost::mutex thread_info_mutex; detail::thread_data_ptr thread_info; - static unsigned __stdcall thread_start_function(void* param); - void start_thread(); explicit thread(detail::thread_data_ptr data); detail::thread_data_ptr get_thread_info() const; + +#ifdef BOOST_HAS_RVALUE_REFS + template + static inline detail::thread_data_ptr make_thread_info(F&& f) + { + return detail::thread_data_ptr(detail::heap_new::type> >(static_cast(f))); + } + static inline detail::thread_data_ptr make_thread_info(void (*f)()) + { + return detail::thread_data_ptr(detail::heap_new >(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::detail::thread_move_t f) + { + return detail::thread_data_ptr(detail::heap_new >(f)); + } + + struct dummy; +#endif public: thread(); ~thread(); +#ifdef BOOST_HAS_RVALUE_REFS template - explicit thread(F f): - thread_info(detail::heap_new >(f)) + thread(F&& f): + thread_info(make_thread_info(static_cast(f))) { start_thread(); } + + thread(thread&& other) + { + thread_info.swap(other.thread_info); + } + + thread& operator=(thread&& other) + { + thread_info=other.thread_info; + other.thread_info.reset((detail::thread_data_base*)0); + return *this; + } + + thread&& move() + { + return static_cast(*this); + } + +#else + template + explicit thread(F f,typename disable_if >, dummy* >::type=0): + thread_info(make_thread_info(f)) + { + start_thread(); + } + template thread(detail::thread_move_t f): - thread_info(detail::heap_new >(f)) + thread_info(make_thread_info(f)) { start_thread(); } - thread(detail::thread_move_t x); - thread& operator=(detail::thread_move_t x); - operator detail::thread_move_t(); - detail::thread_move_t move(); + thread(detail::thread_move_t x) + { + thread_info=x->thread_info; + x->thread_info.reset((detail::thread_data_base*)0); + } + + thread& operator=(detail::thread_move_t x) + { + thread new_thread(x); + swap(new_thread); + return *this; + } + + operator detail::thread_move_t() + { + return move(); + } + + detail::thread_move_t move() + { + detail::thread_move_t x(*this); + return x; + } - void swap(thread& x); +#endif + + template + thread(F f,A1 a1): + 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) + { + thread_info.swap(x.thread_info); + } class id; id get_id() const; @@ -237,47 +297,44 @@ namespace boost static unsigned hardware_concurrency(); - typedef detail::win32::handle native_handle_type; + typedef detail::thread_data_base::native_handle_type native_handle_type; native_handle_type native_handle(); // backwards compatibility bool operator==(const thread& other) const; bool operator!=(const thread& other) const; - static void yield(); - static void sleep(const system_time& xt); + static inline void yield() + { + this_thread::yield(); + } + + static inline void sleep(const system_time& xt) + { + this_thread::sleep(xt); + } // extensions void interrupt(); bool interruption_requested() const; }; - inline detail::thread_move_t move(thread& x) + inline void swap(thread& lhs,thread& rhs) { - return x.move(); + return lhs.swap(rhs); } - inline detail::thread_move_t move(detail::thread_move_t x) +#ifdef BOOST_HAS_RVALUE_REFS + inline thread&& move(thread&& t) { - return x; + return t; } - - template - struct thread::thread_data >: - detail::thread_data_base +#else + inline detail::thread_move_t move(detail::thread_move_t t) { - F& f; - - thread_data(boost::reference_wrapper f_): - f(f_) - {} - - void run() - { - f(); - } - }; - + return t; + } +#endif namespace this_thread { @@ -304,21 +361,13 @@ namespace boost thread::id BOOST_THREAD_DECL get_id(); - bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time); - inline bool interruptible_wait(unsigned long milliseconds) - { - return interruptible_wait(detail::win32::invalid_handle_value,milliseconds); - } - void BOOST_THREAD_DECL interruption_point(); bool BOOST_THREAD_DECL interruption_enabled(); bool BOOST_THREAD_DECL interruption_requested(); - void BOOST_THREAD_DECL yield(); - template - void sleep(TimeDuration const& rel_time) + inline void sleep(xtime const& abs_time) { - interruptible_wait(static_cast(rel_time.total_milliseconds())); + sleep(system_time(abs_time)); } } @@ -334,7 +383,7 @@ namespace boost friend id this_thread::get_id(); public: id(): - thread_data(0) + thread_data() {} bool operator==(const id& y) const @@ -380,15 +429,6 @@ namespace boost return os<<"{Not-any-thread}"; } } - - void interrupt() - { - if(thread_data) - { - thread_data->interrupt(); - } - } - }; inline bool thread::operator==(const thread& other) const @@ -521,4 +561,6 @@ namespace boost #pragma warning(pop) #endif +#include + #endif diff --git a/include/boost/thread/detail/thread_heap_alloc.hpp b/include/boost/thread/detail/thread_heap_alloc.hpp new file mode 100644 index 00000000..2f9bfd5c --- /dev/null +++ b/include/boost/thread/detail/thread_heap_alloc.hpp @@ -0,0 +1,23 @@ +#ifndef BOOST_THREAD_THREAD_HEAP_ALLOC_HPP +#define BOOST_THREAD_THREAD_HEAP_ALLOC_HPP + +// thread_heap_alloc.hpp +// +// (C) Copyright 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) + +#include + +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include +#else +#error "Boost threads unavailable on this platform" +#endif + + +#endif diff --git a/include/boost/thread/detail/tss_hooks.hpp b/include/boost/thread/detail/tss_hooks.hpp index 4b18fe97..c4968442 100644 --- a/include/boost/thread/detail/tss_hooks.hpp +++ b/include/boost/thread/detail/tss_hooks.hpp @@ -8,6 +8,8 @@ #include +#include + #if defined(BOOST_HAS_WINTHREADS) typedef void (__cdecl *thread_exit_handler)(void); @@ -59,7 +61,7 @@ //a method for doing so has been discovered. //May be omitted; may be called multiple times. - extern "C" BOOST_THREAD_DECL void on_thread_exit(void); + extern "C" BOOST_THREAD_DECL void __cdecl on_thread_exit(void); //Function to be called just be fore a thread ends //in an exe or dll that uses Boost.Threads. //Must be called in the context of the thread @@ -75,4 +77,6 @@ #endif //defined(BOOST_HAS_WINTHREADS) +#include + #endif //!defined(BOOST_TLS_HOOKS_HPP) diff --git a/include/boost/thread/exceptions.hpp b/include/boost/thread/exceptions.hpp index e3ff59a5..49e244fe 100644 --- a/include/boost/thread/exceptions.hpp +++ b/include/boost/thread/exceptions.hpp @@ -1,6 +1,6 @@ // Copyright (C) 2001-2003 // William E. Kempf -// Copyright (C) 2007 Anthony Williams +// Copyright (C) 2007-8 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) @@ -19,7 +19,13 @@ #include #include -namespace boost { +#include + +namespace boost +{ + + class BOOST_THREAD_DECL thread_interrupted + {}; class BOOST_THREAD_DECL thread_exception : public std::exception { @@ -99,6 +105,8 @@ public: } // namespace boost +#include + #endif // BOOST_THREAD_CONFIG_PDM070801_H // Change log: diff --git a/include/boost/thread/locks.hpp b/include/boost/thread/locks.hpp index c056206b..b175c859 100644 --- a/include/boost/thread/locks.hpp +++ b/include/boost/thread/locks.hpp @@ -8,10 +8,77 @@ #include #include #include +#include #include +#include + +#include namespace boost { + namespace detail + { + template + struct has_member_lock + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template + static true_type has_member(U*,void (U::*dummy)()=&U::lock); + static false_type has_member(void*); + + BOOST_STATIC_CONSTANT(bool, value=sizeof(has_member_lock::has_member((T*)NULL))==sizeof(true_type)); + }; + + template + struct has_member_unlock + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template + static true_type has_member(U*,void (U::*dummy)()=&U::unlock); + static false_type has_member(void*); + + BOOST_STATIC_CONSTANT(bool, value=sizeof(has_member_unlock::has_member((T*)NULL))==sizeof(true_type)); + }; + + template + struct has_member_try_lock + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template + static true_type has_member(U*,bool (U::*dummy)()=&U::try_lock); + static false_type has_member(void*); + + BOOST_STATIC_CONSTANT(bool, value=sizeof(has_member_try_lock::has_member((T*)NULL))==sizeof(true_type)); + }; + + } + + + template + struct is_mutex_type + { + BOOST_STATIC_CONSTANT(bool, value = detail::has_member_lock::value && + detail::has_member_unlock::value && + detail::has_member_try_lock::value); + + }; + + struct defer_lock_t {}; struct try_to_lock_t @@ -62,6 +129,10 @@ namespace boost explicit unique_lock(unique_lock&); unique_lock& operator=(unique_lock&); public: + unique_lock(): + m(0),is_locked(false) + {} + explicit unique_lock(Mutex& m_): m(&m_),is_locked(false) { @@ -205,15 +276,9 @@ namespace boost }; template - inline detail::thread_move_t > move(unique_lock & x) + void swap(unique_lock& lhs,unique_lock& rhs) { - return x.move(); - } - - template - inline detail::thread_move_t > move(detail::thread_move_t > x) - { - return x; + lhs.swap(rhs); } template @@ -226,6 +291,10 @@ namespace boost explicit shared_lock(shared_lock&); shared_lock& operator=(shared_lock&); public: + shared_lock(): + m(0),is_locked(false) + {} + explicit shared_lock(Mutex& m_): m(&m_),is_locked(false) { @@ -252,26 +321,29 @@ namespace boost m(other->m),is_locked(other->is_locked) { other->is_locked=false; + other->m=0; } shared_lock(detail::thread_move_t > other): m(other->m),is_locked(other->is_locked) { - other->is_locked=false; if(is_locked) { m->unlock_and_lock_shared(); } + other->is_locked=false; + other->m=0; } shared_lock(detail::thread_move_t > other): m(other->m),is_locked(other->is_locked) { - other->is_locked=false; if(is_locked) { m->unlock_upgrade_and_lock_shared(); } + other->is_locked=false; + other->m=0; } operator detail::thread_move_t >() @@ -372,19 +444,6 @@ 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 { @@ -395,33 +454,42 @@ namespace boost explicit upgrade_lock(upgrade_lock&); upgrade_lock& operator=(upgrade_lock&); public: + upgrade_lock(): + m(0),is_locked(false) + {} + explicit upgrade_lock(Mutex& m_): m(&m_),is_locked(false) { lock(); } - upgrade_lock(Mutex& m_,bool do_lock): + upgrade_lock(Mutex& m_,adopt_lock_t): + m(&m_),is_locked(true) + {} + upgrade_lock(Mutex& m_,defer_lock_t): + m(&m_),is_locked(false) + {} + upgrade_lock(Mutex& m_,try_to_lock_t): m(&m_),is_locked(false) { - if(do_lock) - { - lock(); - } + try_lock(); } upgrade_lock(detail::thread_move_t > other): m(other->m),is_locked(other->is_locked) { other->is_locked=false; + other->m=0; } upgrade_lock(detail::thread_move_t > other): m(other->m),is_locked(other->is_locked) { - other->is_locked=false; if(is_locked) { m->unlock_and_lock_upgrade(); } + other->is_locked=false; + other->m=0; } operator detail::thread_move_t >() @@ -508,18 +576,6 @@ namespace boost }; - 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) @@ -584,6 +640,496 @@ namespace boost } }; + namespace detail + { + template + class try_lock_wrapper: + private unique_lock + { + typedef unique_lock base; + public: + try_lock_wrapper() + {} + + explicit try_lock_wrapper(Mutex& m): + base(m,try_to_lock) + {} + + try_lock_wrapper(Mutex& m_,adopt_lock_t): + base(m_,adopt_lock) + {} + try_lock_wrapper(Mutex& m_,defer_lock_t): + base(m_,defer_lock) + {} + try_lock_wrapper(Mutex& m_,try_to_lock_t): + base(m_,try_to_lock) + {} + try_lock_wrapper(detail::thread_move_t > other): + base(detail::thread_move_t(*other)) + {} + + operator detail::thread_move_t >() + { + return move(); + } + + detail::thread_move_t > move() + { + return detail::thread_move_t >(*this); + } + + try_lock_wrapper& operator=(detail::thread_move_t > other) + { + try_lock_wrapper temp(other); + swap(temp); + return *this; + } + + void swap(try_lock_wrapper& other) + { + base::swap(other); + } + void swap(detail::thread_move_t > other) + { + base::swap(*other); + } + + void lock() + { + base::lock(); + } + bool try_lock() + { + return base::try_lock(); + } + void unlock() + { + base::unlock(); + } + bool owns_lock() const + { + return base::owns_lock(); + } + Mutex* mutex() const + { + return base::mutex(); + } + Mutex* release() + { + return base::release(); + } + bool operator!() const + { + return !this->owns_lock(); + } + + typedef typename base::bool_type bool_type; + operator bool_type() const + { + return static_cast(*this); + } + }; + + template + void swap(try_lock_wrapper& lhs,try_lock_wrapper& rhs) + { + lhs.swap(rhs); + } + + template + unsigned try_lock_internal(MutexType1& m1,MutexType2& m2) + { + boost::unique_lock l1(m1,boost::try_to_lock); + if(!l1) + { + return 1; + } + if(!m2.try_lock()) + { + return 2; + } + l1.release(); + return 0; + } + + template + unsigned try_lock_internal(MutexType1& m1,MutexType2& m2,MutexType3& m3) + { + boost::unique_lock l1(m1,boost::try_to_lock); + if(!l1) + { + return 1; + } + if(unsigned const failed_lock=try_lock_internal(m2,m3)) + { + return failed_lock+1; + } + l1.release(); + return 0; + } + + + template + unsigned try_lock_internal(MutexType1& m1,MutexType2& m2,MutexType3& m3, + MutexType4& m4) + { + boost::unique_lock l1(m1,boost::try_to_lock); + if(!l1) + { + return 1; + } + if(unsigned const failed_lock=try_lock_internal(m2,m3,m4)) + { + return failed_lock+1; + } + l1.release(); + return 0; + } + + template + unsigned try_lock_internal(MutexType1& m1,MutexType2& m2,MutexType3& m3, + MutexType4& m4,MutexType5& m5) + { + boost::unique_lock l1(m1,boost::try_to_lock); + if(!l1) + { + return 1; + } + if(unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5)) + { + return failed_lock+1; + } + l1.release(); + return 0; + } + + + template + unsigned lock_helper(MutexType1& m1,MutexType2& m2) + { + boost::unique_lock l1(m1); + if(!m2.try_lock()) + { + return 1; + } + l1.release(); + return 0; + } + + template + unsigned lock_helper(MutexType1& m1,MutexType2& m2,MutexType3& m3) + { + boost::unique_lock l1(m1); + if(unsigned const failed_lock=try_lock_internal(m2,m3)) + { + return failed_lock; + } + l1.release(); + return 0; + } + + template + unsigned lock_helper(MutexType1& m1,MutexType2& m2,MutexType3& m3, + MutexType4& m4) + { + boost::unique_lock l1(m1); + if(unsigned const failed_lock=try_lock_internal(m2,m3,m4)) + { + return failed_lock; + } + l1.release(); + return 0; + } + + template + unsigned lock_helper(MutexType1& m1,MutexType2& m2,MutexType3& m3, + MutexType4& m4,MutexType5& m5) + { + boost::unique_lock l1(m1); + if(unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5)) + { + return failed_lock; + } + l1.release(); + return 0; + } + } + + template + typename enable_if, void>::type lock(MutexType1& m1,MutexType2& m2) + { + unsigned const lock_count=2; + unsigned lock_first=0; + while(true) + { + switch(lock_first) + { + case 0: + lock_first=detail::lock_helper(m1,m2); + if(!lock_first) + return; + break; + case 1: + lock_first=detail::lock_helper(m2,m1); + if(!lock_first) + return; + lock_first=(lock_first+1)%lock_count; + break; + } + } + } + + template + void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3) + { + unsigned const lock_count=3; + unsigned lock_first=0; + while(true) + { + switch(lock_first) + { + case 0: + lock_first=detail::lock_helper(m1,m2,m3); + if(!lock_first) + return; + break; + case 1: + lock_first=detail::lock_helper(m2,m3,m1); + if(!lock_first) + return; + lock_first=(lock_first+1)%lock_count; + break; + case 2: + lock_first=detail::lock_helper(m3,m1,m2); + if(!lock_first) + return; + lock_first=(lock_first+2)%lock_count; + break; + } + } + } + + template + void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3, + MutexType4& m4) + { + unsigned const lock_count=4; + unsigned lock_first=0; + while(true) + { + switch(lock_first) + { + case 0: + lock_first=detail::lock_helper(m1,m2,m3,m4); + if(!lock_first) + return; + break; + case 1: + lock_first=detail::lock_helper(m2,m3,m4,m1); + if(!lock_first) + return; + lock_first=(lock_first+1)%lock_count; + break; + case 2: + lock_first=detail::lock_helper(m3,m4,m1,m2); + if(!lock_first) + return; + lock_first=(lock_first+2)%lock_count; + break; + case 3: + lock_first=detail::lock_helper(m4,m1,m2,m3); + if(!lock_first) + return; + lock_first=(lock_first+3)%lock_count; + break; + } + } + } + + template + void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3, + MutexType4& m4,MutexType5& m5) + { + unsigned const lock_count=5; + unsigned lock_first=0; + while(true) + { + switch(lock_first) + { + case 0: + lock_first=detail::lock_helper(m1,m2,m3,m4,m5); + if(!lock_first) + return; + break; + case 1: + lock_first=detail::lock_helper(m2,m3,m4,m5,m1); + if(!lock_first) + return; + lock_first=(lock_first+1)%lock_count; + break; + case 2: + lock_first=detail::lock_helper(m3,m4,m5,m1,m2); + if(!lock_first) + return; + lock_first=(lock_first+2)%lock_count; + break; + case 3: + lock_first=detail::lock_helper(m4,m5,m1,m2,m3); + if(!lock_first) + return; + lock_first=(lock_first+3)%lock_count; + break; + case 4: + lock_first=detail::lock_helper(m5,m1,m2,m3,m4); + if(!lock_first) + return; + lock_first=(lock_first+4)%lock_count; + break; + } + } + } + + template + typename enable_if, int>::type try_lock(MutexType1& m1,MutexType2& m2) + { + return ((int)detail::try_lock_internal(m1,m2))-1; + } + + template + int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3) + { + return ((int)detail::try_lock_internal(m1,m2,m3))-1; + } + + template + int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3,MutexType4& m4) + { + return ((int)detail::try_lock_internal(m1,m2,m3,m4))-1; + } + + template + int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3,MutexType4& m4,MutexType5& m5) + { + return ((int)detail::try_lock_internal(m1,m2,m3,m4,m5))-1; + } + + + template + typename disable_if, void>::type lock(Iterator begin,Iterator end); + + namespace detail + { + template + struct range_lock_guard + { + Iterator begin; + Iterator end; + + range_lock_guard(Iterator begin_,Iterator end_): + begin(begin_),end(end_) + { + lock(begin,end); + } + + void release() + { + begin=end; + } + + ~range_lock_guard() + { + for(;begin!=end;++begin) + { + begin->unlock(); + } + } + }; + } + + template + typename disable_if, Iterator>::type try_lock(Iterator begin,Iterator end) + { + if(begin==end) + { + return end; + } + typedef typename std::iterator_traits::value_type lock_type; + unique_lock guard(*begin,try_to_lock); + + if(!guard.owns_lock()) + { + return begin; + } + Iterator const failed=try_lock(++begin,end); + if(failed==end) + { + guard.release(); + } + + return failed; + } + + template + typename disable_if, void>::type lock(Iterator begin,Iterator end) + { + typedef typename std::iterator_traits::value_type lock_type; + + if(begin==end) + { + return; + } + bool start_with_begin=true; + Iterator second=begin; + ++second; + Iterator next=second; + + for(;;) + { + unique_lock begin_lock(*begin,defer_lock); + if(start_with_begin) + { + begin_lock.lock(); + Iterator const failed_lock=try_lock(next,end); + if(failed_lock==end) + { + begin_lock.release(); + return; + } + start_with_begin=false; + next=failed_lock; + } + else + { + detail::range_lock_guard guard(next,end); + if(begin_lock.try_lock()) + { + Iterator const failed_lock=try_lock(second,next); + if(failed_lock==next) + { + begin_lock.release(); + guard.release(); + return; + } + start_with_begin=false; + next=failed_lock; + } + else + { + start_with_begin=true; + next=second; + } + } + } + } + } +#include + #endif diff --git a/include/boost/thread/once.hpp b/include/boost/thread/once.hpp index 608b77d6..975304e1 100644 --- a/include/boost/thread/once.hpp +++ b/include/boost/thread/once.hpp @@ -18,6 +18,8 @@ #error "Boost threads unavailable on this platform" #endif +#include + namespace boost { inline void call_once(void (*func)(),once_flag& flag) @@ -26,4 +28,6 @@ namespace boost } } +#include + #endif diff --git a/include/boost/thread/pthread/condition_variable.hpp b/include/boost/thread/pthread/condition_variable.hpp index 52c156bc..2d130a63 100644 --- a/include/boost/thread/pthread/condition_variable.hpp +++ b/include/boost/thread/pthread/condition_variable.hpp @@ -3,32 +3,17 @@ // 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 Anthony Williams +// (C) Copyright 2007-8 Anthony Williams -#include -#include -#include -#include #include "timespec.hpp" #include "pthread_mutex_scoped_lock.hpp" #include "thread_data.hpp" #include "condition_variable_fwd.hpp" +#include + namespace boost { - inline condition_variable::condition_variable() - { - int const res=pthread_cond_init(&cond,NULL); - if(res) - { - throw thread_resource_error(); - } - } - inline condition_variable::~condition_variable() - { - BOOST_VERIFY(!pthread_cond_destroy(&cond)); - } - inline void condition_variable::wait(unique_lock& m) { detail::interruption_checker check_for_interruption(&cond); @@ -175,4 +160,6 @@ namespace boost } +#include + #endif diff --git a/include/boost/thread/pthread/condition_variable_fwd.hpp b/include/boost/thread/pthread/condition_variable_fwd.hpp index 1d1fbdf4..c3941511 100644 --- a/include/boost/thread/pthread/condition_variable_fwd.hpp +++ b/include/boost/thread/pthread/condition_variable_fwd.hpp @@ -3,14 +3,17 @@ // 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 Anthony Williams +// (C) Copyright 2007-8 Anthony Williams +#include #include #include #include #include #include +#include + namespace boost { class condition_variable @@ -22,8 +25,18 @@ namespace boost condition_variable& operator=(condition_variable&); public: - condition_variable(); - ~condition_variable(); + condition_variable() + { + int const res=pthread_cond_init(&cond,NULL); + if(res) + { + throw thread_resource_error(); + } + } + ~condition_variable() + { + BOOST_VERIFY(!pthread_cond_destroy(&cond)); + } void wait(unique_lock& m); @@ -58,9 +71,17 @@ namespace boost return timed_wait(m,get_system_time()+wait_duration,pred); } + typedef pthread_cond_t* native_handle_type; + native_handle_type native_handle() + { + return &cond; + } + void notify_one(); void notify_all(); }; } +#include + #endif diff --git a/include/boost/thread/pthread/mutex.hpp b/include/boost/thread/pthread/mutex.hpp index 89a2bb94..128a9405 100644 --- a/include/boost/thread/pthread/mutex.hpp +++ b/include/boost/thread/pthread/mutex.hpp @@ -1,6 +1,6 @@ #ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP #define BOOST_THREAD_PTHREAD_MUTEX_HPP -// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007-8 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) @@ -11,9 +11,6 @@ #include #include #include -#ifndef WIN32 -#include -#endif #include #include "timespec.hpp" #include "pthread_mutex_scoped_lock.hpp" @@ -24,6 +21,8 @@ #endif #endif +#include + namespace boost { class mutex: @@ -69,7 +68,7 @@ namespace boost } typedef unique_lock scoped_lock; - typedef scoped_lock scoped_try_lock; + typedef detail::try_lock_wrapper scoped_try_lock; }; typedef mutex try_mutex; @@ -136,9 +135,16 @@ namespace boost { struct timespec const timeout=detail::get_timespec(abs_time); int const res=pthread_mutex_timedlock(&m,&timeout); - BOOST_ASSERT(!res || res==EBUSY); + BOOST_ASSERT(!res || res==ETIMEDOUT); return !res; } + + typedef pthread_mutex_t* native_handle_type; + native_handle_type native_handle() + { + return &m; + } + #else void lock() { @@ -187,11 +193,13 @@ namespace boost #endif typedef unique_lock scoped_timed_lock; - typedef scoped_timed_lock scoped_try_lock; + typedef detail::try_lock_wrapper scoped_try_lock; typedef scoped_timed_lock scoped_lock; }; } +#include + #endif diff --git a/include/boost/thread/pthread/once.hpp b/include/boost/thread/pthread/once.hpp index f342ed1d..f278a578 100644 --- a/include/boost/thread/pthread/once.hpp +++ b/include/boost/thread/pthread/once.hpp @@ -3,7 +3,7 @@ // once.hpp // -// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007-8 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -17,7 +17,10 @@ #include #include -namespace boost { +#include + +namespace boost +{ struct once_flag { @@ -82,4 +85,6 @@ namespace boost { } } +#include + #endif diff --git a/include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp b/include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp index 6b474a95..2407f915 100644 --- a/include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp +++ b/include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp @@ -1,6 +1,6 @@ #ifndef BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP #define BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP -// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007-8 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -9,6 +9,8 @@ #include #include +#include + namespace boost { namespace pthread @@ -47,4 +49,6 @@ namespace boost } } +#include + #endif diff --git a/include/boost/thread/pthread/recursive_mutex.hpp b/include/boost/thread/pthread/recursive_mutex.hpp index f496822d..30689460 100644 --- a/include/boost/thread/pthread/recursive_mutex.hpp +++ b/include/boost/thread/pthread/recursive_mutex.hpp @@ -1,6 +1,6 @@ #ifndef BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP #define BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP -// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007-8 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) @@ -11,7 +11,7 @@ #include #include #include -#ifndef WIN32 +#ifndef _WIN32 #include #endif #include @@ -25,6 +25,8 @@ #endif #endif +#include + namespace boost { class recursive_mutex: @@ -76,8 +78,15 @@ namespace boost BOOST_ASSERT(!res || res==EBUSY); return !res; } + + typedef pthread_mutex_t* native_handle_type; + native_handle_type native_handle() + { + return &m; + } + typedef unique_lock scoped_lock; - typedef scoped_lock scoped_try_lock; + typedef detail::try_lock_wrapper scoped_try_lock; }; typedef recursive_mutex recursive_try_mutex; @@ -171,6 +180,13 @@ namespace boost BOOST_ASSERT(!res || res==EBUSY); return !res; } + + typedef pthread_mutex_t* native_handle_type; + native_handle_type native_handle() + { + return &m; + } + #else void lock() { @@ -239,11 +255,12 @@ namespace boost #endif typedef unique_lock scoped_timed_lock; - typedef scoped_timed_lock scoped_try_lock; + typedef detail::try_lock_wrapper scoped_try_lock; typedef scoped_timed_lock scoped_lock; }; } +#include #endif diff --git a/include/boost/thread/pthread/shared_mutex.hpp b/include/boost/thread/pthread/shared_mutex.hpp index 4465f559..74345d88 100644 --- a/include/boost/thread/pthread/shared_mutex.hpp +++ b/include/boost/thread/pthread/shared_mutex.hpp @@ -1,7 +1,7 @@ #ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP #define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP -// (C) Copyright 2006-7 Anthony Williams +// (C) Copyright 2006-8 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -13,6 +13,8 @@ #include #include +#include + namespace boost { class shared_mutex @@ -44,7 +46,7 @@ namespace boost public: shared_mutex() { - state_data state_={0}; + state_data state_={0,0,0,0}; state=state_; } @@ -57,23 +59,11 @@ namespace boost boost::this_thread::disable_interruption do_not_disturb; boost::mutex::scoped_lock lock(state_change); -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable:4127) -#endif - while(true) -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif + while(state.exclusive || state.exclusive_waiting_blocked) { - if(!state.exclusive && !state.exclusive_waiting_blocked) - { - ++state.shared_count; - return; - } - shared_cond.wait(lock); } + ++state.shared_count; } bool try_lock_shared() @@ -96,26 +86,21 @@ namespace boost boost::this_thread::disable_interruption do_not_disturb; boost::mutex::scoped_lock lock(state_change); -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable:4127) -#endif - while(true) -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif + while(state.exclusive || state.exclusive_waiting_blocked) { - if(!state.exclusive && !state.exclusive_waiting_blocked) - { - ++state.shared_count; - return true; - } - if(!shared_cond.timed_wait(lock,timeout)) { return false; } } + ++state.shared_count; + return true; + } + + template + bool timed_lock_shared(TimeDuration const & relative_time) + { + return timed_lock_shared(get_system_time()+relative_time); } void unlock_shared() @@ -144,56 +129,41 @@ namespace boost boost::this_thread::disable_interruption do_not_disturb; boost::mutex::scoped_lock lock(state_change); -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable:4127) -#endif - while(true) -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif + while(state.shared_count || state.exclusive) { - if(state.shared_count || state.exclusive) - { - state.exclusive_waiting_blocked=true; - } - else - { - state.exclusive=true; - return; - } + state.exclusive_waiting_blocked=true; exclusive_cond.wait(lock); } + state.exclusive=true; } bool timed_lock(system_time const& timeout) { boost::this_thread::disable_interruption do_not_disturb; boost::mutex::scoped_lock lock(state_change); - -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable:4127) -#endif - while(true) -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif + + while(state.shared_count || state.exclusive) { - if(state.shared_count || state.exclusive) - { - state.exclusive_waiting_blocked=true; - } - else - { - state.exclusive=true; - return true; - } + state.exclusive_waiting_blocked=true; if(!exclusive_cond.timed_wait(lock,timeout)) { - return false; + if(state.shared_count || state.exclusive) + { + state.exclusive_waiting_blocked=false; + exclusive_cond.notify_one(); + return false; + } + break; } } + state.exclusive=true; + return true; + } + + template + bool timed_lock(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); } bool try_lock() @@ -224,51 +194,38 @@ namespace boost { boost::this_thread::disable_interruption do_not_disturb; boost::mutex::scoped_lock lock(state_change); -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable:4127) -#endif - while(true) -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif + while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) { - if(!state.exclusive && !state.exclusive_waiting_blocked && !state.upgrade) - { - ++state.shared_count; - state.upgrade=true; - return; - } - shared_cond.wait(lock); } + ++state.shared_count; + state.upgrade=true; } bool timed_lock_upgrade(system_time const& timeout) { boost::this_thread::disable_interruption do_not_disturb; boost::mutex::scoped_lock lock(state_change); -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable:4127) -#endif - while(true) -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif + while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) { - if(!state.exclusive && !state.exclusive_waiting_blocked && !state.upgrade) - { - ++state.shared_count; - state.upgrade=true; - return true; - } - if(!shared_cond.timed_wait(lock,timeout)) { - return false; + if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + { + return false; + } + break; } } + ++state.shared_count; + state.upgrade=true; + return true; + } + + template + bool timed_lock_upgrade(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); } bool try_lock_upgrade() @@ -304,23 +261,12 @@ namespace boost boost::this_thread::disable_interruption do_not_disturb; boost::mutex::scoped_lock lock(state_change); --state.shared_count; -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable:4127) -#endif - while(true) -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif + while(state.shared_count) { - if(!state.shared_count) - { - state.upgrade=false; - state.exclusive=true; - break; - } upgrade_cond.wait(lock); } + state.upgrade=false; + state.exclusive=true; } void unlock_and_lock_upgrade() @@ -352,5 +298,6 @@ namespace boost }; } +#include #endif diff --git a/include/boost/thread/pthread/thread.hpp b/include/boost/thread/pthread/thread.hpp deleted file mode 100644 index 8e34c47d..00000000 --- a/include/boost/thread/pthread/thread.hpp +++ /dev/null @@ -1,329 +0,0 @@ -#ifndef BOOST_THREAD_THREAD_PTHREAD_HPP -#define BOOST_THREAD_THREAD_PTHREAD_HPP -// Copyright (C) 2001-2003 -// William E. Kempf -// 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 -#include -#include -#include -#include - -#include -#include -#include -#include -#include "thread_data.hpp" -#include - -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable:4251) -#endif - -namespace boost -{ - class thread; - - namespace detail - { - class thread_id; - } - - namespace this_thread - { - BOOST_THREAD_DECL detail::thread_id get_id(); - } - - namespace detail - { - class thread_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(); - public: - thread_id(): - thread_data() - {} - - bool operator==(const thread_id& y) const - { - return thread_data==y.thread_data; - } - - bool operator!=(const thread_id& y) const - { - 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.thread_data) - { - return os< - struct thread_data: - detail::thread_data_base - { - F f; - - thread_data(F f_): - f(f_) - {} - thread_data(detail::thread_move_t f_): - f(f_) - {} - - void run() - { - f(); - } - }; - - mutable boost::mutex thread_info_mutex; - detail::thread_data_ptr thread_info; - - void start_thread(); - - explicit thread(detail::thread_data_ptr data); - - detail::thread_data_ptr get_thread_info() const; - - public: - thread(); - ~thread(); - - template - explicit thread(F f): - thread_info(new thread_data(f)) - { - start_thread(); - } - template - thread(detail::thread_move_t f): - thread_info(new thread_data(f)) - { - start_thread(); - } - - thread(detail::thread_move_t x); - thread& operator=(detail::thread_move_t x); - operator detail::thread_move_t(); - detail::thread_move_t move(); - - void swap(thread& x); - - typedef detail::thread_id id; - - id get_id() const; - - bool joinable() const; - void join(); - bool timed_join(const system_time& wait_until); - - template - inline bool timed_join(TimeDuration const& rel_time) - { - return timed_join(get_system_time()+rel_time); - } - void detach(); - - static unsigned hardware_concurrency(); - - // backwards compatibility - bool operator==(const thread& other) const; - bool operator!=(const thread& other) const; - - static void sleep(const system_time& xt); - static void yield(); - - // extensions - void interrupt(); - 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 - { - F& f; - - thread_data(boost::reference_wrapper f_): - f(f_) - {} - - void run() - { - f(); - } - }; - - namespace this_thread - { - class BOOST_THREAD_DECL disable_interruption - { - disable_interruption(const disable_interruption&); - disable_interruption& operator=(const disable_interruption&); - - bool interruption_was_enabled; - friend class restore_interruption; - public: - disable_interruption(); - ~disable_interruption(); - }; - - class BOOST_THREAD_DECL restore_interruption - { - restore_interruption(const restore_interruption&); - restore_interruption& operator=(const restore_interruption&); - public: - explicit restore_interruption(disable_interruption& d); - ~restore_interruption(); - }; - - BOOST_THREAD_DECL thread::id get_id(); - - BOOST_THREAD_DECL void interruption_point(); - BOOST_THREAD_DECL bool interruption_enabled(); - BOOST_THREAD_DECL bool interruption_requested(); - - inline void yield() - { - thread::yield(); - } - - template - inline void sleep(TimeDuration const& rel_time) - { - thread::sleep(get_system_time()+rel_time); - } - } - - namespace detail - { - struct thread_exit_function_base - { - virtual ~thread_exit_function_base() - {} - virtual void operator()() const=0; - }; - - template - struct thread_exit_function: - thread_exit_function_base - { - F f; - - thread_exit_function(F f_): - f(f_) - {} - - void operator()() const - { - f(); - } - }; - - BOOST_THREAD_DECL void add_thread_exit_function(thread_exit_function_base*); - } - - namespace this_thread - { - template - inline void at_thread_exit(F f) - { - detail::thread_exit_function_base* const thread_exit_func=new detail::thread_exit_function(f); - detail::add_thread_exit_function(thread_exit_func); - } - } - - class BOOST_THREAD_DECL thread_group - { - public: - thread_group(); - ~thread_group(); - - thread* create_thread(const function0& threadfunc); - void add_thread(thread* thrd); - void remove_thread(thread* thrd); - void join_all(); - void interrupt_all(); - size_t size() const; - - private: - thread_group(thread_group&); - void operator=(thread_group&); - - std::list m_threads; - mutex m_mutex; - }; -} // namespace boost - -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif - - -#endif diff --git a/include/boost/thread/pthread/thread_data.hpp b/include/boost/thread/pthread/thread_data.hpp index 52ca40e5..244035b4 100644 --- a/include/boost/thread/pthread/thread_data.hpp +++ b/include/boost/thread/pthread/thread_data.hpp @@ -6,6 +6,7 @@ // (C) Copyright 2007 Anthony Williams #include +#include #include #include #include @@ -13,11 +14,12 @@ #include #include "condition_variable_fwd.hpp" +#include + namespace boost { - class thread_interrupted - {}; - + class thread; + namespace detail { struct thread_exit_callback_node; @@ -26,7 +28,7 @@ namespace boost struct thread_data_base; typedef boost::shared_ptr thread_data_ptr; - struct thread_data_base: + struct BOOST_THREAD_DECL thread_data_base: enable_shared_from_this { thread_data_ptr self; @@ -51,8 +53,9 @@ namespace boost interrupt_requested(false), current_cond(0) {} - virtual ~thread_data_base() - {} + virtual ~thread_data_base(); + + typedef pthread_t native_handle_type; virtual void run()=0; }; @@ -95,7 +98,21 @@ namespace boost } }; } + + namespace this_thread + { + void BOOST_THREAD_DECL yield(); + + void BOOST_THREAD_DECL sleep(system_time const& abs_time); + + template + inline void sleep(TimeDuration const& rel_time) + { + this_thread::sleep(get_system_time()+rel_time); + } + } } +#include #endif diff --git a/include/boost/thread/pthread/thread_heap_alloc.hpp b/include/boost/thread/pthread/thread_heap_alloc.hpp new file mode 100644 index 00000000..7cc0aa04 --- /dev/null +++ b/include/boost/thread/pthread/thread_heap_alloc.hpp @@ -0,0 +1,242 @@ +// 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 2008 Anthony Williams +#ifndef THREAD_HEAP_ALLOC_PTHREAD_HPP +#define THREAD_HEAP_ALLOC_PTHREAD_HPP + +#include + +namespace boost +{ + namespace detail + { + template + inline T* heap_new() + { + return new T(); + } + +#ifdef BOOST_HAS_RVALUE_REFS + template + inline T* heap_new(A1&& a1) + { + return new T(static_cast(a1)); + } + template + inline T* heap_new(A1&& a1,A2&& a2) + { + return new T(static_cast(a1),static_cast(a2)); + } + template + inline T* heap_new(A1&& a1,A2&& a2,A3&& a3) + { + return new T(static_cast(a1),static_cast(a2), + static_cast(a3)); + } + template + inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4) + { + return new T(static_cast(a1),static_cast(a2), + static_cast(a3),static_cast(a4)); + } +#else + template + inline T* heap_new_impl(A1 a1) + { + return new T(a1); + } + template + inline T* heap_new_impl(A1 a1,A2 a2) + { + return new T(a1,a2); + } + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3) + { + return new T(a1,a2,a3); + } + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4) + { + return new T(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1) + { + return heap_new_impl(a1); + } + template + inline T* heap_new(A1& a1) + { + return heap_new_impl(a1); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1& a1,A2 const& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1 const& a1,A2& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1& a1,A2& a2) + { + return heap_new_impl(a1,a2); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + +#endif + template + inline void heap_delete(T* data) + { + delete data; + } + + template + struct do_heap_delete + { + void operator()(T* data) const + { + detail::heap_delete(data); + } + }; + } +} + +#include + +#endif diff --git a/include/boost/thread/pthread/timespec.hpp b/include/boost/thread/pthread/timespec.hpp index f77bd3b7..d7465c1a 100644 --- a/include/boost/thread/pthread/timespec.hpp +++ b/include/boost/thread/pthread/timespec.hpp @@ -1,6 +1,6 @@ #ifndef BOOST_THREAD_PTHREAD_TIMESPEC_HPP #define BOOST_THREAD_PTHREAD_TIMESPEC_HPP -// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007-8 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -8,6 +8,12 @@ #include #include +#include +#ifndef _WIN32 +#include +#endif + +#include namespace boost { @@ -15,14 +21,16 @@ 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(); - timeout.tv_nsec=time_since_epoch.fractional_seconds()*(1000000000/time_since_epoch.ticks_per_second()); + timeout.tv_nsec=(long)(time_since_epoch.fractional_seconds()*(1000000000l/time_since_epoch.ticks_per_second())); return timeout; } } } +#include + #endif diff --git a/include/boost/thread/pthread/tss.hpp b/include/boost/thread/pthread/tss.hpp deleted file mode 100644 index 8d3bfd36..00000000 --- a/include/boost/thread/pthread/tss.hpp +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef BOOST_THREAD_PTHREAD_TSS_HPP -#define BOOST_THREAD_PTHREAD_TSS_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 Anthony Williams - -#include -#include - -namespace boost -{ - namespace detail - { - struct tss_cleanup_function - { - virtual ~tss_cleanup_function() - {} - - virtual void operator()(void* data)=0; - }; - - BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr func,void* tss_data,bool cleanup_existing); - BOOST_THREAD_DECL void* get_tss_data(void const* key); - } - - template - class thread_specific_ptr - { - private: - thread_specific_ptr(thread_specific_ptr&); - thread_specific_ptr& operator=(thread_specific_ptr&); - - struct delete_data: - detail::tss_cleanup_function - { - void operator()(void* data) - { - delete static_cast(data); - } - }; - - struct run_custom_cleanup_function: - detail::tss_cleanup_function - { - void (*cleanup_function)(T*); - - explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)): - cleanup_function(cleanup_function_) - {} - - void operator()(void* data) - { - cleanup_function(static_cast(data)); - } - }; - - - boost::shared_ptr cleanup; - - public: - thread_specific_ptr(): - cleanup(new delete_data) - {} - explicit thread_specific_ptr(void (*func_)(T*)): - cleanup(new run_custom_cleanup_function(func_)) - {} - ~thread_specific_ptr() - { - reset(); - } - - T* get() const - { - return static_cast(detail::get_tss_data(this)); - } - T* operator->() const - { - return get(); - } - T& operator*() const - { - return *get(); - } - T* release() - { - T* const temp=get(); - detail::set_tss_data(this,boost::shared_ptr(),0,false); - return temp; - } - void reset(T* new_value=0) - { - T* const current_value=get(); - if(current_value!=new_value) - { - detail::set_tss_data(this,cleanup,new_value,true); - } - } - }; -} - -#endif diff --git a/include/boost/thread/thread.hpp b/include/boost/thread/thread.hpp index a1714981..6146132b 100644 --- a/include/boost/thread/thread.hpp +++ b/include/boost/thread/thread.hpp @@ -3,7 +3,7 @@ // thread.hpp // -// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007-8 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -12,11 +12,14 @@ #include #if defined(BOOST_THREAD_PLATFORM_WIN32) -#include +#include #elif defined(BOOST_THREAD_PLATFORM_PTHREAD) -#include +#include #else #error "Boost threads unavailable on this platform" #endif +#include + + #endif diff --git a/include/boost/thread/thread_time.hpp b/include/boost/thread/thread_time.hpp index 5468961f..8b557d5c 100644 --- a/include/boost/thread/thread_time.hpp +++ b/include/boost/thread/thread_time.hpp @@ -9,6 +9,8 @@ #include #include +#include + namespace boost { typedef boost::posix_time::ptime system_time; @@ -43,4 +45,6 @@ namespace boost } +#include + #endif diff --git a/include/boost/thread/tss.hpp b/include/boost/thread/tss.hpp index 131bcde2..4efc6e8b 100644 --- a/include/boost/thread/tss.hpp +++ b/include/boost/thread/tss.hpp @@ -1,18 +1,110 @@ -// 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) - #ifndef BOOST_THREAD_TSS_HPP #define BOOST_THREAD_TSS_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-8 Anthony Williams -#include -#if defined(BOOST_THREAD_PLATFORM_WIN32) -#include -#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) -#include -#else -#error "Boost threads unavailable on this platform" -#endif +#include +#include + +#include + +namespace boost +{ + namespace detail + { + struct tss_cleanup_function + { + virtual ~tss_cleanup_function() + {} + + virtual void operator()(void* data)=0; + }; + + BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr func,void* tss_data,bool cleanup_existing); + BOOST_THREAD_DECL void* get_tss_data(void const* key); + } + + template + class thread_specific_ptr + { + private: + thread_specific_ptr(thread_specific_ptr&); + thread_specific_ptr& operator=(thread_specific_ptr&); + + struct delete_data: + detail::tss_cleanup_function + { + void operator()(void* data) + { + delete static_cast(data); + } + }; + + struct run_custom_cleanup_function: + detail::tss_cleanup_function + { + void (*cleanup_function)(T*); + + explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)): + cleanup_function(cleanup_function_) + {} + + void operator()(void* data) + { + cleanup_function(static_cast(data)); + } + }; + + + boost::shared_ptr cleanup; + + public: + thread_specific_ptr(): + cleanup(detail::heap_new(),detail::do_heap_delete()) + {} + explicit thread_specific_ptr(void (*func_)(T*)) + { + if(func_) + { + cleanup.reset(detail::heap_new(func_),detail::do_heap_delete()); + } + } + ~thread_specific_ptr() + { + reset(); + } + + T* get() const + { + return static_cast(detail::get_tss_data(this)); + } + T* operator->() const + { + return get(); + } + T& operator*() const + { + return *get(); + } + T* release() + { + T* const temp=get(); + detail::set_tss_data(this,boost::shared_ptr(),0,false); + return temp; + } + void reset(T* new_value=0) + { + T* const current_value=get(); + if(current_value!=new_value) + { + detail::set_tss_data(this,cleanup,new_value,true); + } + } + }; +} + +#include #endif diff --git a/include/boost/thread/win32/basic_recursive_mutex.hpp b/include/boost/thread/win32/basic_recursive_mutex.hpp index d2b8e77d..89c5f1dc 100644 --- a/include/boost/thread/win32/basic_recursive_mutex.hpp +++ b/include/boost/thread/win32/basic_recursive_mutex.hpp @@ -3,7 +3,7 @@ // basic_recursive_mutex.hpp // -// (C) Copyright 2006-7 Anthony Williams +// (C) Copyright 2006-8 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -12,6 +12,8 @@ #include "thread_primitives.hpp" #include "basic_timed_mutex.hpp" +#include + namespace boost { namespace detail @@ -123,4 +125,6 @@ namespace boost #define BOOST_BASIC_RECURSIVE_MUTEX_INITIALIZER {0} +#include + #endif diff --git a/include/boost/thread/win32/basic_timed_mutex.hpp b/include/boost/thread/win32/basic_timed_mutex.hpp index 207c0920..a218233c 100644 --- a/include/boost/thread/win32/basic_timed_mutex.hpp +++ b/include/boost/thread/win32/basic_timed_mutex.hpp @@ -3,7 +3,7 @@ // basic_timed_mutex_win32.hpp // -// (C) Copyright 2006 Anthony Williams +// (C) Copyright 2006-8 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -15,13 +15,18 @@ #include #include +#include + namespace boost { namespace detail { struct basic_timed_mutex { - BOOST_STATIC_CONSTANT(long,lock_flag_value=0x80000000); + BOOST_STATIC_CONSTANT(unsigned char,lock_flag_bit=31); + BOOST_STATIC_CONSTANT(unsigned char,event_set_flag_bit=30); + BOOST_STATIC_CONSTANT(long,lock_flag_value=1<offset) + long const offset=lock_flag_value; + long const old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,lock_flag_value); + if(!(old_count&event_set_flag_value) && (old_count>offset)) { - win32::SetEvent(get_event()); + if(!win32::interlocked_bit_test_and_set(&active_count,event_set_flag_bit)) + { + win32::SetEvent(get_event()); + } } } @@ -182,4 +177,6 @@ namespace boost #define BOOST_BASIC_TIMED_MUTEX_INITIALIZER {0} +#include + #endif diff --git a/include/boost/thread/win32/condition_variable.hpp b/include/boost/thread/win32/condition_variable.hpp index 6bd4efd6..6e676b49 100644 --- a/include/boost/thread/win32/condition_variable.hpp +++ b/include/boost/thread/win32/condition_variable.hpp @@ -3,7 +3,7 @@ // 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 Anthony Williams +// (C) Copyright 2007-8 Anthony Williams #include #include "thread_primitives.hpp" @@ -14,85 +14,118 @@ #include #include "interlocked_read.hpp" #include +#include +#include + +#include 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 + typedef basic_cv_list_entry list_entry; + + typedef boost::intrusive_ptr entry_ptr; + typedef std::vector generation_list; + + generation_list generations; + detail::win32::handle_manager wake_sem; + + void wake_waiters(long count_to_wake) { - detail::win32::handle semaphore; - long count; - bool notified; - - list_entry(): - semaphore(0),count(0),notified(0) - {} - }; - - BOOST_STATIC_CONSTANT(unsigned,generation_count=3); - - list_entry generations[generation_count]; - detail::win32::handle wake_sem; - - static bool no_waiters(list_entry const& entry) - { - return entry.count==0; - } - - void shift_generations_down() - { - list_entry* const last_active_entry=std::remove_if(generations,generations+generation_count,no_waiters); - if(last_active_entry==generations+generation_count) - { - broadcast_entry(generations[generation_count-1],false); - } - else - { - active_generation_count=unsigned(last_active_entry-generations)+1; - } - -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable:4996) -#endif - std::copy_backward(generations,generations+active_generation_count-1,generations+active_generation_count); -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif - generations[0]=list_entry(); - } - - void broadcast_entry(list_entry& entry,bool wake) - { - long const count_to_wake=entry.count; detail::interlocked_write_release(&total_count,total_count-count_to_wake); - if(wake) - { - detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0); - } - detail::win32::ReleaseSemaphore(entry.semaphore,count_to_wake,0); - entry.count=0; - dispose_entry(entry); + detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0); } - - - void dispose_entry(list_entry& entry) - { - if(entry.semaphore) - { - BOOST_VERIFY(detail::win32::CloseHandle(entry.semaphore)); - entry.semaphore=0; - } - entry.notified=false; - } - + template struct relocker { @@ -116,75 +149,78 @@ namespace boost } private: + relocker(relocker&); void operator=(relocker&); }; - template - void start_wait_loop_first_time(relocker& locker, - detail::win32::handle_manager& local_wake_sem) + entry_ptr get_wait_entry() { - locker.unlock(); + boost::lock_guard internal_lock(internal_mutex); + if(!wake_sem) { wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); BOOST_ASSERT(wake_sem); } - local_wake_sem=detail::win32::duplicate_handle(wake_sem); - - if(generations[0].notified) + + detail::interlocked_write_release(&total_count,total_count+1); + if(generations.empty() || generations.back()->is_notified()) { - shift_generations_down(); + entry_ptr new_entry(new list_entry(wake_sem)); + generations.push_back(new_entry); + return new_entry; } - else if(!active_generation_count) + else { - active_generation_count=1; + generations.back()->add_waiter(); + return generations.back(); } } - template - void start_wait_loop(relocker& locker, - detail::win32::handle_manager& local_wake_sem, - detail::win32::handle_manager& sem) + struct entry_manager { - boost::mutex::scoped_lock internal_lock(internal_mutex); - detail::interlocked_write_release(&total_count,total_count+1); - if(!local_wake_sem) + entry_ptr const entry; + + entry_manager(entry_ptr const& entry_): + entry(entry_) + {} + + ~entry_manager() { - start_wait_loop_first_time(locker,local_wake_sem); + entry->remove_waiter(); } - if(!generations[0].semaphore) + + list_entry* operator->() { - generations[0].semaphore=detail::win32::create_anonymous_semaphore(0,LONG_MAX); - BOOST_ASSERT(generations[0].semaphore); + return entry.get(); } - ++generations[0].count; - sem=detail::win32::duplicate_handle(generations[0].semaphore); - } + + private: + void operator=(entry_manager&); + entry_manager(entry_manager&); + }; + protected: template bool do_wait(lock_type& lock,timeout wait_until) { - detail::win32::handle_manager local_wake_sem; - detail::win32::handle_manager sem; - bool woken=false; - relocker locker(lock); - + + entry_manager entry(get_wait_entry()); + + locker.unlock(); + + bool woken=false; while(!woken) { - start_wait_loop(locker,local_wake_sem,sem); - - if(!this_thread::interruptible_wait(sem,wait_until)) + if(!entry->wait(wait_until)) { return false; } - unsigned long const woken_result=detail::win32::WaitForSingleObject(local_wake_sem,0); - BOOST_ASSERT(woken_result==detail::win32::timeout || woken_result==0); - - woken=(woken_result==0); + woken=entry->woken(); } return woken; } @@ -202,45 +238,33 @@ namespace boost basic_condition_variable(const basic_condition_variable& other); basic_condition_variable& operator=(const basic_condition_variable& other); + public: basic_condition_variable(): total_count(0),active_generation_count(0),wake_sem(0) {} ~basic_condition_variable() - { - for(unsigned i=0;i internal_lock(internal_mutex); + if(!total_count) { - list_entry& entry=generations[generation-1]; - if(entry.count) - { - detail::interlocked_write_release(&total_count,total_count-1); - entry.notified=true; - detail::win32::ReleaseSemaphore(entry.semaphore,1,0); - if(!--entry.count) - { - dispose_entry(entry); - if(generation==active_generation_count) - { - --active_generation_count; - } - } - } + return; } + wake_waiters(1); + + for(generation_list::iterator it=generations.begin(), + end=generations.end(); + it!=end;++it) + { + (*it)->release(1); + } + generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end()); } } @@ -248,16 +272,20 @@ namespace boost { if(detail::interlocked_read_acquire(&total_count)) { - boost::mutex::scoped_lock internal_lock(internal_mutex); - for(unsigned generation=active_generation_count;generation!=0;--generation) + boost::lock_guard internal_lock(internal_mutex); + if(!total_count) { - list_entry& entry=generations[generation-1]; - if(entry.count) - { - broadcast_entry(entry,true); - } + return; } - active_generation_count=0; + wake_waiters(total_count); + for(generation_list::iterator it=generations.begin(), + end=generations.end(); + it!=end;++it) + { + (*it)->release_waiters(); + } + generations.clear(); + wake_sem=detail::win32::handle(0); } } @@ -265,9 +293,18 @@ namespace boost } class condition_variable: - public detail::basic_condition_variable + private detail::basic_condition_variable { + private: + condition_variable(condition_variable&); + void operator=(condition_variable&); public: + condition_variable() + {} + + using detail::basic_condition_variable::notify_one; + using detail::basic_condition_variable::notify_all; + void wait(unique_lock& m) { do_wait(m,detail::timeout::sentinel()); @@ -313,9 +350,18 @@ namespace boost }; class condition_variable_any: - public detail::basic_condition_variable + private detail::basic_condition_variable { + private: + condition_variable_any(condition_variable_any&); + void operator=(condition_variable_any&); public: + condition_variable_any() + {} + + using detail::basic_condition_variable::notify_one; + using detail::basic_condition_variable::notify_all; + template void wait(lock_type& m) { @@ -367,4 +413,6 @@ namespace boost } +#include + #endif diff --git a/include/boost/thread/win32/interlocked_read.hpp b/include/boost/thread/win32/interlocked_read.hpp index 72315f60..133fb6f9 100644 --- a/include/boost/thread/win32/interlocked_read.hpp +++ b/include/boost/thread/win32/interlocked_read.hpp @@ -3,12 +3,16 @@ // interlocked_read_win32.hpp // -// (C) Copyright 2005-7 Anthony Williams +// (C) Copyright 2005-8 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 + #ifdef BOOST_MSVC extern "C" void _ReadWriteBarrier(void); @@ -46,8 +50,6 @@ namespace boost #else -#include - namespace boost { namespace detail @@ -73,5 +75,6 @@ namespace boost #endif +#include #endif diff --git a/include/boost/thread/win32/mutex.hpp b/include/boost/thread/win32/mutex.hpp index 29759a9a..3fa11d9c 100644 --- a/include/boost/thread/win32/mutex.hpp +++ b/include/boost/thread/win32/mutex.hpp @@ -10,6 +10,8 @@ #include #include +#include + namespace boost { namespace detail @@ -32,7 +34,7 @@ namespace boost } typedef unique_lock scoped_lock; - typedef scoped_lock scoped_try_lock; + typedef detail::try_lock_wrapper scoped_try_lock; }; typedef mutex try_mutex; @@ -53,9 +55,11 @@ namespace boost } typedef unique_lock scoped_timed_lock; - typedef scoped_timed_lock scoped_try_lock; + typedef detail::try_lock_wrapper scoped_try_lock; typedef scoped_timed_lock scoped_lock; }; } +#include + #endif diff --git a/include/boost/thread/win32/once.hpp b/include/boost/thread/win32/once.hpp index 719eaea5..a6fcc94d 100644 --- a/include/boost/thread/win32/once.hpp +++ b/include/boost/thread/win32/once.hpp @@ -18,6 +18,8 @@ #include #include +#include + #ifdef BOOST_NO_STDC_NAMESPACE namespace std { @@ -129,4 +131,6 @@ namespace boost } } +#include + #endif diff --git a/include/boost/thread/win32/recursive_mutex.hpp b/include/boost/thread/win32/recursive_mutex.hpp index 855dd15b..2360a92b 100644 --- a/include/boost/thread/win32/recursive_mutex.hpp +++ b/include/boost/thread/win32/recursive_mutex.hpp @@ -15,6 +15,8 @@ #include #include +#include + namespace boost { class recursive_mutex: @@ -32,7 +34,7 @@ namespace boost } typedef unique_lock scoped_lock; - typedef scoped_lock scoped_try_lock; + typedef detail::try_lock_wrapper scoped_try_lock; }; typedef recursive_mutex recursive_try_mutex; @@ -52,10 +54,11 @@ namespace boost } typedef unique_lock scoped_timed_lock; - typedef scoped_timed_lock scoped_try_lock; + typedef detail::try_lock_wrapper scoped_try_lock; typedef scoped_timed_lock scoped_lock; }; } +#include #endif diff --git a/include/boost/thread/win32/shared_mutex.hpp b/include/boost/thread/win32/shared_mutex.hpp index 1c9fd1be..9f3c489e 100644 --- a/include/boost/thread/win32/shared_mutex.hpp +++ b/include/boost/thread/win32/shared_mutex.hpp @@ -15,6 +15,8 @@ #include #include +#include + namespace boost { class shared_mutex: @@ -23,12 +25,12 @@ namespace boost private: struct state_data { - unsigned shared_count:11; - unsigned shared_waiting:11; - unsigned exclusive:1; - unsigned upgrade:1; - unsigned exclusive_waiting:7; - unsigned exclusive_waiting_blocked:1; + unsigned shared_count:11, + shared_waiting:11, + exclusive:1, + upgrade:1, + exclusive_waiting:7, + exclusive_waiting_blocked:1; friend bool operator==(state_data const& lhs,state_data const& rhs) { @@ -120,6 +122,12 @@ namespace boost BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel())); } + template + bool timed_lock_shared(TimeDuration const & relative_time) + { + return timed_lock_shared(get_system_time()+relative_time); + } + bool timed_lock_shared(boost::system_time const& wait_until) { #ifdef BOOST_MSVC @@ -269,6 +277,12 @@ namespace boost BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel())); } + template + bool timed_lock(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); + } + bool timed_lock(boost::system_time const& wait_until) { #ifdef BOOST_MSVC @@ -325,7 +339,10 @@ namespace boost { if(new_state.exclusive_waiting) { - --new_state.exclusive_waiting; + if(!--new_state.exclusive_waiting) + { + new_state.exclusive_waiting_blocked=false; + } } } else @@ -617,5 +634,6 @@ namespace boost }; } +#include #endif diff --git a/include/boost/thread/win32/thread_data.hpp b/include/boost/thread/win32/thread_data.hpp new file mode 100644 index 00000000..1a6a1e03 --- /dev/null +++ b/include/boost/thread/win32/thread_data.hpp @@ -0,0 +1,178 @@ +#ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP +#define BOOST_THREAD_PTHREAD_THREAD_DATA_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 2008 Anthony Williams + +#include +#include +#include +#include "thread_primitives.hpp" +#include "thread_heap_alloc.hpp" + +#include + +namespace boost +{ + namespace detail + { + struct thread_exit_callback_node; + struct tss_data_node; + + struct thread_data_base; + void intrusive_ptr_add_ref(thread_data_base * p); + void intrusive_ptr_release(thread_data_base * p); + + struct thread_data_base + { + long count; + detail::win32::handle_manager thread_handle; + detail::win32::handle_manager interruption_handle; + boost::detail::thread_exit_callback_node* thread_exit_callbacks; + boost::detail::tss_data_node* tss_data; + bool interruption_enabled; + unsigned id; + + thread_data_base(): + count(0),thread_handle(detail::win32::invalid_handle_value), + interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)), + thread_exit_callbacks(0),tss_data(0), + interruption_enabled(true), + id(0) + {} + virtual ~thread_data_base() + {} + + friend void intrusive_ptr_add_ref(thread_data_base * p) + { + BOOST_INTERLOCKED_INCREMENT(&p->count); + } + + friend void intrusive_ptr_release(thread_data_base * p) + { + if(!BOOST_INTERLOCKED_DECREMENT(&p->count)) + { + detail::heap_delete(p); + } + } + + void interrupt() + { + BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0); + } + + typedef detail::win32::handle native_handle_type; + + virtual void run()=0; + }; + + typedef boost::intrusive_ptr thread_data_ptr; + + struct timeout + { + unsigned long start; + uintmax_t milliseconds; + bool relative; + boost::system_time abs_time; + + static unsigned long const max_non_infinite_wait=0xfffffffe; + + timeout(uintmax_t milliseconds_): + start(win32::GetTickCount()), + milliseconds(milliseconds_), + relative(true), + abs_time(boost::get_system_time()) + {} + + timeout(boost::system_time const& abs_time_): + start(win32::GetTickCount()), + milliseconds(0), + relative(false), + abs_time(abs_time_) + {} + + struct remaining_time + { + bool more; + unsigned long milliseconds; + + remaining_time(uintmax_t remaining): + more(remaining>max_non_infinite_wait), + milliseconds(more?max_non_infinite_wait:(unsigned long)remaining) + {} + }; + + remaining_time remaining_milliseconds() const + { + if(is_sentinel()) + { + return remaining_time(win32::infinite); + } + else if(relative) + { + unsigned long const now=win32::GetTickCount(); + unsigned long const elapsed=now-start; + return remaining_time((elapsed + inline void sleep(TimeDuration const& rel_time) + { + interruptible_wait(static_cast(rel_time.total_milliseconds())); + } + inline void sleep(system_time const& abs_time) + { + interruptible_wait(abs_time); + } + } + +} + +#include + +#endif diff --git a/include/boost/thread/win32/thread_heap_alloc.hpp b/include/boost/thread/win32/thread_heap_alloc.hpp index ee47e0e6..9f8186f5 100644 --- a/include/boost/thread/win32/thread_heap_alloc.hpp +++ b/include/boost/thread/win32/thread_heap_alloc.hpp @@ -49,6 +49,8 @@ namespace boost #endif +#include + namespace boost { namespace detail @@ -69,7 +71,7 @@ namespace boost } template - T* heap_new() + inline T* heap_new() { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); try @@ -84,8 +86,72 @@ namespace boost } } +#ifdef BOOST_HAS_RVALUE_REFS template - T* heap_new(A1 a1) + inline T* heap_new(A1&& a1) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(static_cast(a1)); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + template + inline T* heap_new(A1&& a1,A2&& a2) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(static_cast(a1),static_cast(a2)); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + template + inline T* heap_new(A1&& a1,A2&& a2,A3&& a3) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(static_cast(a1),static_cast(a2), + static_cast(a3)); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + template + inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(static_cast(a1),static_cast(a2), + static_cast(a3),static_cast(a4)); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } +#else + template + inline T* heap_new_impl(A1 a1) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); try @@ -99,9 +165,9 @@ namespace boost throw; } } - + template - T* heap_new(A1 a1,A2 a2) + inline T* heap_new_impl(A1 a1,A2 a2) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); try @@ -117,7 +183,7 @@ namespace boost } template - T* heap_new(A1 a1,A2 a2,A3 a3) + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); try @@ -131,9 +197,9 @@ namespace boost throw; } } - + template - T* heap_new(A1 a1,A2 a2,A3 a3,A4 a4) + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); try @@ -147,9 +213,168 @@ namespace boost throw; } } + + + template + inline T* heap_new(A1 const& a1) + { + return heap_new_impl(a1); + } + template + inline T* heap_new(A1& a1) + { + return heap_new_impl(a1); + } + template + inline T* heap_new(A1 const& a1,A2 const& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1& a1,A2 const& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1 const& a1,A2& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1& a1,A2& a2) + { + return heap_new_impl(a1,a2); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + +#endif template - void heap_delete(T* data) + inline void heap_delete(T* data) { data->~T(); free_raw_heap_memory(data); @@ -166,5 +391,7 @@ namespace boost } } +#include + #endif diff --git a/include/boost/thread/win32/thread_primitives.hpp b/include/boost/thread/win32/thread_primitives.hpp index f8f66b15..de58c45b 100644 --- a/include/boost/thread/win32/thread_primitives.hpp +++ b/include/boost/thread/win32/thread_primitives.hpp @@ -13,10 +13,12 @@ #include #include #include +#include #include #if defined( BOOST_USE_WINDOWS_H ) # include + namespace boost { namespace detail @@ -146,6 +148,8 @@ namespace boost # error "Win32 functions not available" #endif +#include + namespace boost { namespace detail @@ -277,5 +281,117 @@ namespace boost } } +#if defined(BOOST_MSVC) && (_MSC_VER>=1400) && !defined(UNDER_CE) +#if _MSC_VER==1400 +extern "C" unsigned char _interlockedbittestandset(long *a,long b); +extern "C" unsigned char _interlockedbittestandreset(long *a,long b); +#else +extern "C" unsigned char _interlockedbittestandset(volatile long *a,long b); +extern "C" unsigned char _interlockedbittestandreset(volatile long *a,long b); +#endif + +#pragma intrinsic(_interlockedbittestandset) +#pragma intrinsic(_interlockedbittestandreset) + +namespace boost +{ + namespace detail + { + namespace win32 + { + inline bool interlocked_bit_test_and_set(long* x,long bit) + { + return _interlockedbittestandset(x,bit)!=0; + } + + inline bool interlocked_bit_test_and_reset(long* x,long bit) + { + return _interlockedbittestandreset(x,bit)!=0; + } + + } + } +} +#define BOOST_THREAD_BTS_DEFINED +#elif (defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)) && defined(_M_IX86) +namespace boost +{ + namespace detail + { + namespace win32 + { + inline bool interlocked_bit_test_and_set(long* x,long bit) + { + __asm { + mov eax,bit; + mov edx,x; + lock bts [edx],eax; + setc al; + }; + } + + inline bool interlocked_bit_test_and_reset(long* x,long bit) + { + __asm { + mov eax,bit; + mov edx,x; + lock btr [edx],eax; + setc al; + }; + } + + } + } +} +#define BOOST_THREAD_BTS_DEFINED +#endif + +#ifndef BOOST_THREAD_BTS_DEFINED + +namespace boost +{ + namespace detail + { + namespace win32 + { + inline bool interlocked_bit_test_and_set(long* x,long bit) + { + long const value=1< #endif diff --git a/include/boost/thread/win32/tss.hpp b/include/boost/thread/win32/tss.hpp deleted file mode 100644 index c6ce5c12..00000000 --- a/include/boost/thread/win32/tss.hpp +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef BOOST_THREAD_WIN32_TSS_HPP -#define BOOST_THREAD_WIN32_TSS_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 Anthony Williams - -#include -#include "thread_heap_alloc.hpp" - -namespace boost -{ - namespace detail - { - struct tss_cleanup_function - { - virtual ~tss_cleanup_function() - {} - - virtual void operator()(void* data)=0; - }; - - BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr func,void* tss_data,bool cleanup_existing); - BOOST_THREAD_DECL void* get_tss_data(void const* key); - } - - template - class thread_specific_ptr - { - private: - thread_specific_ptr(thread_specific_ptr&); - thread_specific_ptr& operator=(thread_specific_ptr&); - - struct delete_data: - detail::tss_cleanup_function - { - void operator()(void* data) - { - delete static_cast(data); - } - }; - - struct run_custom_cleanup_function: - detail::tss_cleanup_function - { - void (*cleanup_function)(T*); - - explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)): - cleanup_function(cleanup_function_) - {} - - void operator()(void* data) - { - cleanup_function(static_cast(data)); - } - }; - - - boost::shared_ptr cleanup; - - public: - thread_specific_ptr(): - cleanup(detail::heap_new(),detail::do_heap_delete()) - {} - explicit thread_specific_ptr(void (*func_)(T*)): - cleanup(detail::heap_new(func_),detail::do_heap_delete()) - {} - ~thread_specific_ptr() - { - reset(); - } - - T* get() const - { - return static_cast(detail::get_tss_data(this)); - } - T* operator->() const - { - return get(); - } - T& operator*() const - { - return *get(); - } - T* release() - { - T* const temp=get(); - detail::set_tss_data(this,boost::shared_ptr(),0,false); - return temp; - } - void reset(T* new_value=0) - { - T* const current_value=get(); - if(current_value!=new_value) - { - detail::set_tss_data(this,cleanup,new_value,true); - } - } - }; -} - - -#endif diff --git a/include/boost/thread/xtime.hpp b/include/boost/thread/xtime.hpp index e3970758..7cc6272d 100644 --- a/include/boost/thread/xtime.hpp +++ b/include/boost/thread/xtime.hpp @@ -1,6 +1,6 @@ // Copyright (C) 2001-2003 // William E. Kempf -// Copyright (C) 2007 Anthony Williams +// Copyright (C) 2007-8 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) @@ -14,6 +14,8 @@ #include #include +#include + namespace boost { enum xtime_clock_types @@ -56,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()); @@ -85,4 +87,6 @@ inline int xtime_cmp(const xtime& xt1, const xtime& xt2) } // namespace boost +#include + #endif //BOOST_XTIME_WEK070601_HPP diff --git a/src/pthread/thread.cpp b/src/pthread/thread.cpp index 754e0af5..2ceb68af 100644 --- a/src/pthread/thread.cpp +++ b/src/pthread/thread.cpp @@ -1,6 +1,6 @@ // Copyright (C) 2001-2003 // William E. Kempf -// Copyright (C) 2007 Anthony Williams +// Copyright (C) 2007-8 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) @@ -18,7 +18,7 @@ #elif defined(__APPLE__) || defined(__FreeBSD__) #include #include -#elif defined(__sun) +#elif defined(__sun) || defined(__CYGWIN__) #include #endif @@ -28,6 +28,9 @@ namespace boost { namespace detail { + thread_data_base::~thread_data_base() + {} + struct thread_exit_callback_node { boost::detail::thread_exit_function_base* func; @@ -119,7 +122,7 @@ namespace boost { void* thread_proxy(void* param) { - boost::shared_ptr thread_info = static_cast(param)->self; + boost::detail::thread_data_ptr thread_info = static_cast(param)->self; thread_info->self.reset(); detail::set_current_thread_data(thread_info.get()); try @@ -153,6 +156,10 @@ namespace boost void run() {} + + private: + externally_launched_thread(externally_launched_thread&); + void operator=(externally_launched_thread&); }; detail::thread_data_base* make_external_thread_data() @@ -196,47 +203,6 @@ namespace boost detach(); } - thread::thread(detail::thread_move_t x) - { - lock_guard lock(x->thread_info_mutex); - thread_info=x->thread_info; - x->thread_info.reset(); - } - - thread& thread::operator=(detail::thread_move_t x) - { - thread new_thread(x); - swap(new_thread); - return *this; - } - - thread::operator detail::thread_move_t() - { - return move(); - } - - detail::thread_move_t thread::move() - { - detail::thread_move_t x(*this); - return x; - } - - void thread::swap(thread& x) - { - thread_info.swap(x.thread_info); - } - - - bool thread::operator==(const thread& other) const - { - return get_id()==other.get_id(); - } - - bool thread::operator!=(const thread& other) const - { - return !operator==(other); - } - detail::thread_data_ptr thread::get_thread_info() const { lock_guard l(thread_info_mutex); @@ -361,57 +327,61 @@ namespace boost } } - void thread::sleep(const system_time& st) + namespace this_thread { - detail::thread_data_base* const thread_info=detail::get_current_thread_data(); - if(thread_info) + void sleep(const system_time& st) { - unique_lock lk(thread_info->sleep_mutex); - while(thread_info->sleep_condition.timed_wait(lk,st)); - } - else - { - xtime const xt=get_xtime(st); - - for (int foo=0; foo < 5; ++foo) + detail::thread_data_base* const thread_info=detail::get_current_thread_data(); + + if(thread_info) { + unique_lock lk(thread_info->sleep_mutex); + while(thread_info->sleep_condition.timed_wait(lk,st)); + } + else + { + xtime const xt=get_xtime(st); + + for (int foo=0; foo < 5; ++foo) + { # if defined(BOOST_HAS_PTHREAD_DELAY_NP) - timespec ts; - to_timespec_duration(xt, ts); - BOOST_VERIFY(!pthread_delay_np(&ts)); + timespec ts; + to_timespec_duration(xt, ts); + BOOST_VERIFY(!pthread_delay_np(&ts)); # elif defined(BOOST_HAS_NANOSLEEP) - timespec ts; - to_timespec_duration(xt, ts); + timespec ts; + to_timespec_duration(xt, ts); - // nanosleep takes a timespec that is an offset, not - // an absolute time. - nanosleep(&ts, 0); + // nanosleep takes a timespec that is an offset, not + // an absolute time. + nanosleep(&ts, 0); # else - mutex mx; - mutex::scoped_lock lock(mx); - condition cond; - cond.timed_wait(lock, xt); + mutex mx; + mutex::scoped_lock lock(mx); + condition cond; + cond.timed_wait(lock, xt); # endif - xtime cur; - xtime_get(&cur, TIME_UTC); - if (xtime_cmp(xt, cur) <= 0) - return; + xtime cur; + xtime_get(&cur, TIME_UTC); + if (xtime_cmp(xt, cur) <= 0) + return; + } } } - } - void thread::yield() - { + void yield() + { # if defined(BOOST_HAS_SCHED_YIELD) - BOOST_VERIFY(!sched_yield()); + BOOST_VERIFY(!sched_yield()); # elif defined(BOOST_HAS_PTHREAD_YIELD) - BOOST_VERIFY(!pthread_yield()); + BOOST_VERIFY(!pthread_yield()); # else - xtime xt; - xtime_get(&xt, TIME_UTC); - sleep(xt); + xtime xt; + xtime_get(&xt, TIME_UTC); + sleep(xt); # endif + } } unsigned thread::hardware_concurrency() @@ -424,7 +394,7 @@ namespace boost int count; size_t size=sizeof(count); return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count; -#elif defined(__sun) +#elif defined(__sun) || defined(__CYGWIN__) int const count=sysconf(_SC_NPROCESSORS_ONLN); return (count>0)?count:0; #else @@ -472,6 +442,21 @@ namespace boost return false; } } + + thread::native_handle_type thread::native_handle() + { + detail::thread_data_ptr const local_thread_info=get_thread_info(); + if(local_thread_info) + { + lock_guard lk(local_thread_info->data_mutex); + return local_thread_info->thread_handle; + } + else + { + return pthread_t(); + } + } + namespace this_thread @@ -607,85 +592,85 @@ namespace boost } } - thread_group::thread_group() - { - } +// thread_group::thread_group() +// { +// } - thread_group::~thread_group() - { - // We shouldn't have to scoped_lock here, since referencing this object - // from another thread while we're deleting it in the current thread is - // going to lead to undefined behavior any way. - for (std::list::iterator it = m_threads.begin(); - it != m_threads.end(); ++it) - { - delete (*it); - } - } +// thread_group::~thread_group() +// { +// // We shouldn't have to scoped_lock here, since referencing this object +// // from another thread while we're deleting it in the current thread is +// // going to lead to undefined behavior any way. +// for (std::list::iterator it = m_threads.begin(); +// it != m_threads.end(); ++it) +// { +// delete (*it); +// } +// } - thread* thread_group::create_thread(const function0& threadfunc) - { - // No scoped_lock required here since the only "shared data" that's - // modified here occurs inside add_thread which does scoped_lock. - std::auto_ptr thrd(new thread(threadfunc)); - add_thread(thrd.get()); - return thrd.release(); - } +// thread* thread_group::create_thread(const function0& threadfunc) +// { +// // No scoped_lock required here since the only "shared data" that's +// // modified here occurs inside add_thread which does scoped_lock. +// std::auto_ptr thrd(new thread(threadfunc)); +// add_thread(thrd.get()); +// return thrd.release(); +// } - void thread_group::add_thread(thread* thrd) - { - mutex::scoped_lock scoped_lock(m_mutex); +// void thread_group::add_thread(thread* thrd) +// { +// mutex::scoped_lock scoped_lock(m_mutex); - // For now we'll simply ignore requests to add a thread object multiple - // times. Should we consider this an error and either throw or return an - // error value? - std::list::iterator it = std::find(m_threads.begin(), - m_threads.end(), thrd); - BOOST_ASSERT(it == m_threads.end()); - if (it == m_threads.end()) - m_threads.push_back(thrd); - } +// // For now we'll simply ignore requests to add a thread object multiple +// // times. Should we consider this an error and either throw or return an +// // error value? +// std::list::iterator it = std::find(m_threads.begin(), +// m_threads.end(), thrd); +// BOOST_ASSERT(it == m_threads.end()); +// if (it == m_threads.end()) +// m_threads.push_back(thrd); +// } - void thread_group::remove_thread(thread* thrd) - { - mutex::scoped_lock scoped_lock(m_mutex); +// void thread_group::remove_thread(thread* thrd) +// { +// mutex::scoped_lock scoped_lock(m_mutex); - // For now we'll simply ignore requests to remove a thread object that's - // not in the group. Should we consider this an error and either throw or - // return an error value? - std::list::iterator it = std::find(m_threads.begin(), - m_threads.end(), thrd); - BOOST_ASSERT(it != m_threads.end()); - if (it != m_threads.end()) - m_threads.erase(it); - } +// // For now we'll simply ignore requests to remove a thread object that's +// // not in the group. Should we consider this an error and either throw or +// // return an error value? +// std::list::iterator it = std::find(m_threads.begin(), +// m_threads.end(), thrd); +// BOOST_ASSERT(it != m_threads.end()); +// if (it != m_threads.end()) +// m_threads.erase(it); +// } - void thread_group::join_all() - { - mutex::scoped_lock scoped_lock(m_mutex); - for (std::list::iterator it = m_threads.begin(); - it != m_threads.end(); ++it) - { - (*it)->join(); - } - } +// void thread_group::join_all() +// { +// mutex::scoped_lock scoped_lock(m_mutex); +// for (std::list::iterator it = m_threads.begin(); +// it != m_threads.end(); ++it) +// { +// (*it)->join(); +// } +// } - void thread_group::interrupt_all() - { - boost::lock_guard guard(m_mutex); +// void thread_group::interrupt_all() +// { +// boost::lock_guard guard(m_mutex); - for(std::list::iterator it=m_threads.begin(),end=m_threads.end(); - it!=end; - ++it) - { - (*it)->interrupt(); - } - } +// for(std::list::iterator it=m_threads.begin(),end=m_threads.end(); +// it!=end; +// ++it) +// { +// (*it)->interrupt(); +// } +// } - size_t thread_group::size() const - { - return m_threads.size(); - } +// size_t thread_group::size() const +// { +// return m_threads.size(); +// } } diff --git a/src/tss_null.cpp b/src/tss_null.cpp index 3288c679..ff13b30f 100644 --- a/src/tss_null.cpp +++ b/src/tss_null.cpp @@ -6,7 +6,7 @@ #include -#if defined(BOOST_HAS_WINTHREADS) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST)) && (!defined(_MSC_VER) || defined(UNDER_CE)) +#if defined(BOOST_HAS_WINTHREADS) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST) || defined(UNDER_CE)) && (!defined(_MSC_VER) || defined(UNDER_CE)) /* This file is a "null" implementation of tss cleanup; it's diff --git a/src/win32/thread.cpp b/src/win32/thread.cpp index d64c78dd..e54b847d 100644 --- a/src/win32/thread.cpp +++ b/src/win32/thread.cpp @@ -81,25 +81,6 @@ namespace boost } - void thread::yield() - { - this_thread::yield(); - } - - void thread::sleep(const system_time& target) - { - system_time const now(get_system_time()); - - if(target<=now) - { - this_thread::yield(); - } - else - { - this_thread::sleep(target-now); - } - } - namespace detail { struct thread_exit_callback_node @@ -164,26 +145,24 @@ namespace boost set_current_thread_data(0); } - } - - - unsigned __stdcall thread::thread_start_function(void* param) - { - detail::thread_data_base* const thread_info(reinterpret_cast(param)); - set_current_thread_data(thread_info); - try + unsigned __stdcall thread_start_function(void* param) { - thread_info->run(); + detail::thread_data_base* const thread_info(reinterpret_cast(param)); + set_current_thread_data(thread_info); + try + { + thread_info->run(); + } + catch(thread_interrupted const&) + { + } + catch(...) + { + std::terminate(); + } + run_thread_exit_callbacks(); + return 0; } - catch(thread_interrupted const&) - { - } - catch(...) - { - std::terminate(); - } - run_thread_exit_callbacks(); - return 0; } thread::thread() @@ -218,6 +197,9 @@ namespace boost void run() {} + private: + externally_launched_thread(externally_launched_thread&); + void operator=(externally_launched_thread&); }; void make_external_thread_data() @@ -244,36 +226,6 @@ namespace boost detach(); } - thread::thread(detail::thread_move_t x) - { - lock_guard lock(x->thread_info_mutex); - thread_info=x->thread_info; - x->thread_info=0; - } - - thread& thread::operator=(detail::thread_move_t x) - { - thread new_thread(x); - swap(new_thread); - return *this; - } - - thread::operator detail::thread_move_t() - { - return move(); - } - - detail::thread_move_t thread::move() - { - detail::thread_move_t x(*this); - return x; - } - - void thread::swap(thread& x) - { - thread_info.swap(x.thread_info); - } - thread::id thread::get_id() const { return thread::id(get_thread_info()); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index d9e4bcb9..a6a769cb 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -22,22 +22,24 @@ project : requirements /boost/test//boost_unit_test_framework/static multi ; - + rule thread-run ( sources ) { return - [ run $(sources) ../build//boost_thread ] - [ run $(sources) ../src/tss_null.cpp ../build//boost_thread/static - : : : : $(sources[1]:B)_lib ] - ; + [ run $(sources) ../build//boost_thread ] + [ run $(sources) ../src/tss_null.cpp ../build//boost_thread/static + : : : : $(sources[1]:B)_lib ] + ; } - + { 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_thread_launching.cpp ] + [ thread-run test_thread_mf.cpp ] [ thread-run test_move_function.cpp ] [ thread-run test_mutex.cpp ] [ thread-run test_condition_notify_one.cpp ] @@ -47,9 +49,13 @@ rule thread-run ( sources ) [ thread-run test_tss.cpp ] [ thread-run test_once.cpp ] [ thread-run test_xtime.cpp ] - [ thread-run test_barrier.cpp ] + [ thread-run test_barrier.cpp ] [ thread-run test_shared_mutex.cpp ] [ thread-run test_shared_mutex_part_2.cpp ] + [ thread-run test_shared_mutex_timed_locks.cpp ] [ thread-run test_lock_concept.cpp ] + [ thread-run test_generic_locks.cpp ] + [ compile-fail no_implicit_move_from_lvalue_thread.cpp ] + [ compile-fail no_implicit_assign_from_lvalue_thread.cpp ] ; } diff --git a/test/no_implicit_assign_from_lvalue_thread.cpp b/test/no_implicit_assign_from_lvalue_thread.cpp new file mode 100644 index 00000000..02b6893e --- /dev/null +++ b/test/no_implicit_assign_from_lvalue_thread.cpp @@ -0,0 +1,15 @@ +// 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) +#include + +void do_nothing() +{} + +void test() +{ + boost::thread t1(do_nothing); + boost::thread t2; + t2=t1; +} diff --git a/test/no_implicit_move_from_lvalue_thread.cpp b/test/no_implicit_move_from_lvalue_thread.cpp new file mode 100644 index 00000000..5c4600ec --- /dev/null +++ b/test/no_implicit_move_from_lvalue_thread.cpp @@ -0,0 +1,14 @@ +// 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) +#include + +void do_nothing() +{} + +void test() +{ + boost::thread t1(do_nothing); + boost::thread t2(t1); +} diff --git a/test/shared_mutex_locking_thread.hpp b/test/shared_mutex_locking_thread.hpp index 0d071bd8..98a415b1 100644 --- a/test/shared_mutex_locking_thread.hpp +++ b/test/shared_mutex_locking_thread.hpp @@ -66,5 +66,67 @@ private: void operator=(locking_thread&); }; +class simple_writing_thread +{ + boost::shared_mutex& rwm; + boost::mutex& finish_mutex; + boost::mutex& unblocked_mutex; + unsigned& unblocked_count; + + void operator=(simple_writing_thread&); + +public: + simple_writing_thread(boost::shared_mutex& rwm_, + boost::mutex& finish_mutex_, + boost::mutex& unblocked_mutex_, + unsigned& unblocked_count_): + rwm(rwm_),finish_mutex(finish_mutex_), + unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_) + {} + + void operator()() + { + boost::unique_lock lk(rwm); + + { + boost::mutex::scoped_lock ulk(unblocked_mutex); + ++unblocked_count; + } + + boost::mutex::scoped_lock flk(finish_mutex); + } +}; + +class simple_reading_thread +{ + boost::shared_mutex& rwm; + boost::mutex& finish_mutex; + boost::mutex& unblocked_mutex; + unsigned& unblocked_count; + + void operator=(simple_reading_thread&); + +public: + simple_reading_thread(boost::shared_mutex& rwm_, + boost::mutex& finish_mutex_, + boost::mutex& unblocked_mutex_, + unsigned& unblocked_count_): + rwm(rwm_),finish_mutex(finish_mutex_), + unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_) + {} + + void operator()() + { + boost::shared_lock lk(rwm); + + { + boost::mutex::scoped_lock ulk(unblocked_mutex); + ++unblocked_count; + } + + boost::mutex::scoped_lock flk(finish_mutex); + } +}; + #endif diff --git a/test/test_condition_notify_all.cpp b/test/test_condition_notify_all.cpp index 22074b44..11a983eb 100644 --- a/test/test_condition_notify_all.cpp +++ b/test/test_condition_notify_all.cpp @@ -159,6 +159,47 @@ void do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate( } } +namespace +{ + boost::mutex multiple_wake_mutex; + boost::condition_variable multiple_wake_cond; + unsigned multiple_wake_count=0; + + void wait_for_condvar_and_increase_count() + { + boost::mutex::scoped_lock lk(multiple_wake_mutex); + multiple_wake_cond.wait(lk); + ++multiple_wake_count; + } + +} + + +void do_test_notify_all_following_notify_one_wakes_all_threads() +{ + boost::thread thread1(wait_for_condvar_and_increase_count); + boost::thread thread2(wait_for_condvar_and_increase_count); + + boost::this_thread::sleep(boost::posix_time::milliseconds(200)); + multiple_wake_cond.notify_one(); + + boost::thread thread3(wait_for_condvar_and_increase_count); + + boost::this_thread::sleep(boost::posix_time::milliseconds(200)); + multiple_wake_cond.notify_one(); + multiple_wake_cond.notify_all(); + boost::this_thread::sleep(boost::posix_time::milliseconds(200)); + + { + boost::mutex::scoped_lock lk(multiple_wake_mutex); + BOOST_CHECK(multiple_wake_count==3); + } + + thread1.join(); + thread2.join(); + thread3.join(); +} + void test_condition_notify_all() { timed_test(&do_test_condition_notify_all_wakes_from_wait, timeout_seconds); @@ -166,6 +207,7 @@ void test_condition_notify_all() timed_test(&do_test_condition_notify_all_wakes_from_timed_wait, timeout_seconds); timed_test(&do_test_condition_notify_all_wakes_from_timed_wait_with_predicate, timeout_seconds); timed_test(&do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate, timeout_seconds); + timed_test(&do_test_notify_all_following_notify_one_wakes_all_threads, timeout_seconds); } diff --git a/test/test_condition_notify_one.cpp b/test/test_condition_notify_one.cpp index 45447bd4..a5d82bec 100644 --- a/test/test_condition_notify_one.cpp +++ b/test/test_condition_notify_one.cpp @@ -92,6 +92,47 @@ void do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate( BOOST_CHECK(data.woken); } +namespace +{ + boost::mutex multiple_wake_mutex; + boost::condition_variable multiple_wake_cond; + unsigned multiple_wake_count=0; + + void wait_for_condvar_and_increase_count() + { + boost::mutex::scoped_lock lk(multiple_wake_mutex); + multiple_wake_cond.wait(lk); + ++multiple_wake_count; + } + +} + + +void do_test_multiple_notify_one_calls_wakes_multiple_threads() +{ + boost::thread thread1(wait_for_condvar_and_increase_count); + boost::thread thread2(wait_for_condvar_and_increase_count); + + boost::this_thread::sleep(boost::posix_time::milliseconds(200)); + multiple_wake_cond.notify_one(); + + boost::thread thread3(wait_for_condvar_and_increase_count); + + boost::this_thread::sleep(boost::posix_time::milliseconds(200)); + multiple_wake_cond.notify_one(); + multiple_wake_cond.notify_one(); + boost::this_thread::sleep(boost::posix_time::milliseconds(200)); + + { + boost::mutex::scoped_lock lk(multiple_wake_mutex); + BOOST_CHECK(multiple_wake_count==3); + } + + thread1.join(); + thread2.join(); + thread3.join(); +} + void test_condition_notify_one() { timed_test(&do_test_condition_notify_one_wakes_from_wait, timeout_seconds, execution_monitor::use_mutex); @@ -99,6 +140,7 @@ void test_condition_notify_one() timed_test(&do_test_condition_notify_one_wakes_from_timed_wait, timeout_seconds, execution_monitor::use_mutex); timed_test(&do_test_condition_notify_one_wakes_from_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex); timed_test(&do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex); + timed_test(&do_test_multiple_notify_one_calls_wakes_multiple_threads, timeout_seconds, execution_monitor::use_mutex); } diff --git a/test/test_generic_locks.cpp b/test/test_generic_locks.cpp new file mode 100644 index 00000000..a091976e --- /dev/null +++ b/test/test_generic_locks.cpp @@ -0,0 +1,513 @@ +// (C) Copyright 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) + +#include +#include +#include +#include +#include + +void test_lock_two_uncontended() +{ + boost::mutex m1,m2; + + boost::mutex::scoped_lock l1(m1,boost::defer_lock), + l2(m2,boost::defer_lock); + + BOOST_CHECK(!l1.owns_lock()); + BOOST_CHECK(!l2.owns_lock()); + + boost::lock(l1,l2); + + BOOST_CHECK(l1.owns_lock()); + BOOST_CHECK(l2.owns_lock()); +} + +struct wait_data +{ + boost::mutex m; + bool flag; + boost::condition_variable cond; + + wait_data(): + flag(false) + {} + + void wait() + { + boost::mutex::scoped_lock l(m); + while(!flag) + { + cond.wait(l); + } + } + + template + bool timed_wait(Duration d) + { + boost::system_time const target=boost::get_system_time()+d; + + boost::mutex::scoped_lock l(m); + while(!flag) + { + if(!cond.timed_wait(l,target)) + { + return flag; + } + } + return true; + } + + void signal() + { + boost::mutex::scoped_lock l(m); + flag=true; + cond.notify_all(); + } +}; + + +void lock_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,wait_data* locked,wait_data* quit) +{ + boost::lock_guard l1(*m1); + boost::this_thread::sleep(boost::posix_time::milliseconds(500)); + boost::lock_guard l2(*m2); + locked->signal(); + quit->wait(); +} + +void lock_pair(boost::mutex* m1,boost::mutex* m2) +{ + boost::lock(*m1,*m2); + boost::mutex::scoped_lock l1(*m1,boost::adopt_lock), + l2(*m2,boost::adopt_lock); +} + +void test_lock_two_other_thread_locks_in_order() +{ + boost::mutex m1,m2; + wait_data locked; + wait_data release; + + boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release); + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + + boost::thread t2(lock_pair,&m1,&m2); + BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1))); + + release.signal(); + + BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1))); + + t.join(); +} + +void test_lock_two_other_thread_locks_in_opposite_order() +{ + boost::mutex m1,m2; + wait_data locked; + wait_data release; + + boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release); + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + + boost::thread t2(lock_pair,&m2,&m1); + BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1))); + + release.signal(); + + BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1))); + + t.join(); +} + +void test_lock_five_uncontended() +{ + boost::mutex m1,m2,m3,m4,m5; + + boost::mutex::scoped_lock l1(m1,boost::defer_lock), + l2(m2,boost::defer_lock), + l3(m3,boost::defer_lock), + l4(m4,boost::defer_lock), + l5(m5,boost::defer_lock); + + BOOST_CHECK(!l1.owns_lock()); + BOOST_CHECK(!l2.owns_lock()); + BOOST_CHECK(!l3.owns_lock()); + BOOST_CHECK(!l4.owns_lock()); + BOOST_CHECK(!l5.owns_lock()); + + boost::lock(l1,l2,l3,l4,l5); + + BOOST_CHECK(l1.owns_lock()); + BOOST_CHECK(l2.owns_lock()); + BOOST_CHECK(l3.owns_lock()); + BOOST_CHECK(l4.owns_lock()); + BOOST_CHECK(l5.owns_lock()); +} + +void lock_five_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5, + wait_data* locked,wait_data* quit) +{ + boost::lock_guard l1(*m1); + boost::this_thread::sleep(boost::posix_time::milliseconds(500)); + boost::lock_guard l2(*m2); + boost::this_thread::sleep(boost::posix_time::milliseconds(500)); + boost::lock_guard l3(*m3); + boost::this_thread::sleep(boost::posix_time::milliseconds(500)); + boost::lock_guard l4(*m4); + boost::this_thread::sleep(boost::posix_time::milliseconds(500)); + boost::lock_guard l5(*m5); + locked->signal(); + quit->wait(); +} + +void lock_five(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5) +{ + boost::lock(*m1,*m2,*m3,*m4,*m5); + m1->unlock(); + m2->unlock(); + m3->unlock(); + m4->unlock(); + m5->unlock(); +} + +void test_lock_five_other_thread_locks_in_order() +{ + boost::mutex m1,m2,m3,m4,m5; + wait_data locked; + wait_data release; + + boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release); + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + + boost::thread t2(lock_five,&m1,&m2,&m3,&m4,&m5); + BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3))); + + release.signal(); + + BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3))); + + t.join(); +} + +void test_lock_five_other_thread_locks_in_different_order() +{ + boost::mutex m1,m2,m3,m4,m5; + wait_data locked; + wait_data release; + + boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release); + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + + boost::thread t2(lock_five,&m5,&m1,&m4,&m2,&m3); + BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3))); + + release.signal(); + + BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3))); + + t.join(); +} + +void lock_n(boost::mutex* mutexes,unsigned count) +{ + boost::lock(mutexes,mutexes+count); + for(unsigned i=0;i l1(m1,boost::defer_lock), + l2(m2,boost::defer_lock); + + int const res=boost::try_lock(l1,l2); + + BOOST_CHECK(res==0); + BOOST_CHECK(m1.is_locked); + BOOST_CHECK(!m2.is_locked); + BOOST_CHECK(!l1.owns_lock()); + BOOST_CHECK(!l2.owns_lock()); +} +void test_try_lock_two_second_locked() +{ + dummy_mutex m1,m2; + m2.lock(); + + boost::unique_lock l1(m1,boost::defer_lock), + l2(m2,boost::defer_lock); + + int const res=boost::try_lock(l1,l2); + + BOOST_CHECK(res==1); + BOOST_CHECK(!m1.is_locked); + BOOST_CHECK(m2.is_locked); + BOOST_CHECK(!l1.owns_lock()); + BOOST_CHECK(!l2.owns_lock()); +} + +void test_try_lock_three() +{ + int const num_mutexes=3; + + for(int i=-1;i=0) + { + mutexes[i].lock(); + } + boost::unique_lock l1(mutexes[0],boost::defer_lock), + l2(mutexes[1],boost::defer_lock), + l3(mutexes[2],boost::defer_lock); + + int const res=boost::try_lock(l1,l2,l3); + + BOOST_CHECK(res==i); + for(int j=0;j=0) + { + mutexes[i].lock(); + } + boost::unique_lock l1(mutexes[0],boost::defer_lock), + l2(mutexes[1],boost::defer_lock), + l3(mutexes[2],boost::defer_lock), + l4(mutexes[3],boost::defer_lock); + + int const res=boost::try_lock(l1,l2,l3,l4); + + BOOST_CHECK(res==i); + for(int j=0;j=0) + { + mutexes[i].lock(); + } + boost::unique_lock l1(mutexes[0],boost::defer_lock), + l2(mutexes[1],boost::defer_lock), + l3(mutexes[2],boost::defer_lock), + l4(mutexes[3],boost::defer_lock), + l5(mutexes[4],boost::defer_lock); + + int const res=boost::try_lock(l1,l2,l3,l4,l5); + + BOOST_CHECK(res==i); + for(int j=0;jadd(BOOST_TEST_CASE(&test_lock_two_uncontended)); + test->add(BOOST_TEST_CASE(&test_lock_two_other_thread_locks_in_order)); + test->add(BOOST_TEST_CASE(&test_lock_two_other_thread_locks_in_opposite_order)); + test->add(BOOST_TEST_CASE(&test_lock_five_uncontended)); + test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_order)); + test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_different_order)); + test->add(BOOST_TEST_CASE(&test_lock_five_in_range)); + test->add(BOOST_TEST_CASE(&test_lock_ten_in_range)); + test->add(BOOST_TEST_CASE(&test_lock_ten_other_thread_locks_in_different_order)); + test->add(BOOST_TEST_CASE(&test_try_lock_two_uncontended)); + test->add(BOOST_TEST_CASE(&test_try_lock_two_first_locked)); + test->add(BOOST_TEST_CASE(&test_try_lock_two_second_locked)); + test->add(BOOST_TEST_CASE(&test_try_lock_three)); + test->add(BOOST_TEST_CASE(&test_try_lock_four)); + test->add(BOOST_TEST_CASE(&test_try_lock_five)); + + return test; +} diff --git a/test/test_lock_concept.cpp b/test/test_lock_concept.cpp index b0f5dc72..8b16dfb5 100644 --- a/test/test_lock_concept.cpp +++ b/test/test_lock_concept.cpp @@ -1,4 +1,4 @@ -// (C) Copyright 2006-7 Anthony Williams +// (C) Copyright 2006-8 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) @@ -7,7 +7,9 @@ #include #include #include +#include #include +#include template struct test_initially_locked @@ -22,6 +24,64 @@ struct test_initially_locked } }; +template +struct test_initially_unlocked_if_other_thread_has_lock +{ + Mutex m; + boost::mutex done_mutex; + bool done; + bool locked; + boost::condition_variable done_cond; + + test_initially_unlocked_if_other_thread_has_lock(): + done(false),locked(false) + {} + + void locking_thread() + { + Lock lock(m); + + boost::lock_guard lk(done_mutex); + locked=lock.owns_lock(); + done=true; + done_cond.notify_one(); + } + + bool is_done() const + { + return done; + } + + + void operator()() + { + Lock lock(m); + + typedef test_initially_unlocked_if_other_thread_has_lock this_type; + + boost::thread t(&this_type::locking_thread,this); + + try + { + { + boost::mutex::scoped_lock lk(done_mutex); + BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2), + boost::bind(&this_type::is_done,this))); + BOOST_CHECK(!locked); + } + + lock.unlock(); + t.join(); + } + catch(...) + { + lock.unlock(); + t.join(); + throw; + } + } +}; + template struct test_initially_unlocked_with_defer_lock_parameter { @@ -125,11 +185,51 @@ struct test_throws_if_unlock_called_when_already_unlocked BOOST_CHECK_THROW( lock.unlock(), boost::lock_error ); } }; +template +struct test_default_constructed_has_no_mutex_and_unlocked +{ + void operator()() const + { + Lock l; + BOOST_CHECK(!l.mutex()); + BOOST_CHECK(!l.owns_lock()); + }; +}; + + +template +struct test_locks_can_be_swapped +{ + void operator()() const + { + Mutex m1; + Mutex m2; + Lock l1(m1); + Lock l2(m2); + + BOOST_CHECK_EQUAL(l1.mutex(),&m1); + BOOST_CHECK_EQUAL(l2.mutex(),&m2); + + l1.swap(l2); + + BOOST_CHECK_EQUAL(l1.mutex(),&m2); + BOOST_CHECK_EQUAL(l2.mutex(),&m1); + + swap(l1,l2); + + BOOST_CHECK_EQUAL(l1.mutex(),&m1); + BOOST_CHECK_EQUAL(l2.mutex(),&m2); + + } +}; + + BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex) { typedef typename Mutex::scoped_lock Lock; + test_default_constructed_has_no_mutex_and_unlocked()(); test_initially_locked()(); test_initially_unlocked_with_defer_lock_parameter()(); test_initially_locked_with_adopt_lock_parameter()(); @@ -137,13 +237,16 @@ BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex) test_locked_after_lock_called()(); test_throws_if_lock_called_when_already_locked()(); test_throws_if_unlock_called_when_already_unlocked()(); + test_locks_can_be_swapped()(); } BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_try_lock_concept,Mutex) { typedef typename Mutex::scoped_try_lock Lock; + test_default_constructed_has_no_mutex_and_unlocked()(); test_initially_locked()(); + test_initially_unlocked_if_other_thread_has_lock()(); test_initially_unlocked_with_defer_lock_parameter()(); test_initially_locked_with_adopt_lock_parameter()(); test_unlocked_after_unlock_called()(); @@ -152,6 +255,7 @@ BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_try_lock_concept,Mutex) test_throws_if_lock_called_when_already_locked()(); test_throws_if_try_lock_called_when_already_locked()(); test_throws_if_unlock_called_when_already_unlocked()(); + test_locks_can_be_swapped()(); } boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) diff --git a/test/test_move_function.cpp b/test/test_move_function.cpp index 153a4cf1..6400ada8 100644 --- a/test/test_move_function.cpp +++ b/test/test_move_function.cpp @@ -1,10 +1,11 @@ -// Copyright (C) 2007 Anthony Williams +// Copyright (C) 2007-8 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 +#include void do_nothing() {} @@ -20,13 +21,36 @@ void test_thread_move_from_lvalue_on_construction() dest.join(); } +void test_thread_move_from_lvalue_on_assignment() +{ + boost::thread src(do_nothing); + boost::thread::id src_id=src.get_id(); + boost::thread dest; + 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(); +} + +boost::thread start_thread() +{ + return boost::thread(do_nothing); +} + void test_thread_move_from_rvalue_on_construction() { - boost::thread x(boost::move(boost::thread(do_nothing))); + boost::thread x(start_thread()); BOOST_CHECK(x.get_id()!=boost::thread::id()); x.join(); } +void test_thread_move_from_rvalue_using_explicit_move() +{ + boost::thread x(boost::move(start_thread())); + BOOST_CHECK(x.get_id()!=boost::thread::id()); + x.join(); +} void test_unique_lock_move_from_lvalue_on_construction() { @@ -42,6 +66,48 @@ void test_unique_lock_move_from_lvalue_on_construction() BOOST_CHECK(l2.mutex()==&m); } +boost::unique_lock get_lock(boost::mutex& m) +{ + return boost::unique_lock(m); +} + + +void test_unique_lock_move_from_rvalue_on_construction() +{ + boost::mutex m; + boost::unique_lock l(get_lock(m)); + BOOST_CHECK(l.owns_lock()); + BOOST_CHECK(l.mutex()==&m); +} + +namespace user_test_ns +{ + template + T move(T& t) + { + return t.move(); + } + + bool move_called=false; + + struct nc: + public boost::shared_ptr + { + nc move() + { + move_called=true; + return nc(); + } + }; +} + +void test_move_for_user_defined_type_unaffected() +{ + user_test_ns::nc src; + user_test_ns::nc dest=move(src); + BOOST_CHECK(user_test_ns::move_called); +} + boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { boost::unit_test_framework::test_suite* test = @@ -49,6 +115,10 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) 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_thread_move_from_rvalue_using_explicit_move)); + test->add(BOOST_TEST_CASE(test_thread_move_from_lvalue_on_assignment)); test->add(BOOST_TEST_CASE(test_unique_lock_move_from_lvalue_on_construction)); + test->add(BOOST_TEST_CASE(test_unique_lock_move_from_rvalue_on_construction)); + test->add(BOOST_TEST_CASE(test_move_for_user_defined_type_unaffected)); return test; } diff --git a/test/test_shared_mutex_part_2.cpp b/test/test_shared_mutex_part_2.cpp index ae7348df..2daa8582 100644 --- a/test/test_shared_mutex_part_2.cpp +++ b/test/test_shared_mutex_part_2.cpp @@ -107,40 +107,6 @@ void test_can_lock_upgrade_if_currently_locked_shared() CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count+1); } -namespace -{ - class simple_writing_thread - { - boost::shared_mutex& rwm; - boost::mutex& finish_mutex; - boost::mutex& unblocked_mutex; - unsigned& unblocked_count; - - void operator=(simple_writing_thread&); - - public: - simple_writing_thread(boost::shared_mutex& rwm_, - boost::mutex& finish_mutex_, - boost::mutex& unblocked_mutex_, - unsigned& unblocked_count_): - rwm(rwm_),finish_mutex(finish_mutex_), - unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_) - {} - - void operator()() - { - boost::unique_lock lk(rwm); - - { - boost::mutex::scoped_lock ulk(unblocked_mutex); - ++unblocked_count; - } - - boost::mutex::scoped_lock flk(finish_mutex); - } - }; -} - void test_if_other_thread_has_write_lock_try_lock_shared_returns_false() { @@ -175,40 +141,6 @@ void test_if_no_thread_has_lock_try_lock_shared_returns_true() } } -namespace -{ - class simple_reading_thread - { - boost::shared_mutex& rwm; - boost::mutex& finish_mutex; - boost::mutex& unblocked_mutex; - unsigned& unblocked_count; - - void operator=(simple_reading_thread&); - - public: - simple_reading_thread(boost::shared_mutex& rwm_, - boost::mutex& finish_mutex_, - boost::mutex& unblocked_mutex_, - unsigned& unblocked_count_): - rwm(rwm_),finish_mutex(finish_mutex_), - unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_) - {} - - void operator()() - { - boost::shared_lock lk(rwm); - - { - boost::mutex::scoped_lock ulk(unblocked_mutex); - ++unblocked_count; - } - - boost::mutex::scoped_lock flk(finish_mutex); - } - }; -} - void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true() { @@ -232,33 +164,6 @@ void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true() writer.join(); } -void test_timed_lock_shared_times_out_if_write_lock_held() -{ - boost::shared_mutex rw_mutex; - boost::mutex finish_mutex; - boost::mutex unblocked_mutex; - unsigned unblocked_count=0; - boost::mutex::scoped_lock finish_lock(finish_mutex); - boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); - boost::thread::sleep(delay(1)); - CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); - - boost::system_time const start=boost::get_system_time(); - boost::system_time const timeout=start+boost::posix_time::milliseconds(2000); - boost::posix_time::milliseconds const timeout_resolution(20); - bool const timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout); - BOOST_CHECK((timeout-timeout_resolution)add(BOOST_TEST_CASE(&test_if_other_thread_has_write_lock_try_lock_shared_returns_false)); test->add(BOOST_TEST_CASE(&test_if_no_thread_has_lock_try_lock_shared_returns_true)); test->add(BOOST_TEST_CASE(&test_if_other_thread_has_shared_lock_try_lock_shared_returns_true)); - test->add(BOOST_TEST_CASE(&test_timed_lock_shared_times_out_if_write_lock_held)); return test; } diff --git a/test/test_shared_mutex_timed_locks.cpp b/test/test_shared_mutex_timed_locks.cpp new file mode 100644 index 00000000..04efbc9b --- /dev/null +++ b/test/test_shared_mutex_timed_locks.cpp @@ -0,0 +1,268 @@ +// (C) Copyright 2006-7 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 +#include "util.inl" +#include "shared_mutex_locking_thread.hpp" + +#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \ + { \ + boost::mutex::scoped_lock lock(mutex_name); \ + BOOST_CHECK_EQUAL(value,expected_value); \ + } + + +void test_timed_lock_shared_times_out_if_write_lock_held() +{ + boost::shared_mutex rw_mutex; + boost::mutex finish_mutex; + boost::mutex unblocked_mutex; + unsigned unblocked_count=0; + boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); + + boost::system_time const start=boost::get_system_time(); + boost::system_time const timeout=start+boost::posix_time::milliseconds(500); + boost::posix_time::milliseconds const timeout_resolution(50); + bool timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout); + BOOST_CHECK((timeout-timeout_resolution)add(BOOST_TEST_CASE(&test_timed_lock_shared_times_out_if_write_lock_held)); + test->add(BOOST_TEST_CASE(&test_timed_lock_shared_succeeds_if_no_lock_held)); + test->add(BOOST_TEST_CASE(&test_timed_lock_shared_succeeds_if_read_lock_held)); + test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_if_write_lock_held)); + test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_if_read_lock_held)); + test->add(BOOST_TEST_CASE(&test_timed_lock_succeeds_if_no_lock_held)); + test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_but_read_lock_succeeds_if_read_lock_held)); + + return test; +} 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; } diff --git a/test/test_thread_launching.cpp b/test/test_thread_launching.cpp new file mode 100644 index 00000000..4582e657 --- /dev/null +++ b/test/test_thread_launching.cpp @@ -0,0 +1,226 @@ +// Copyright (C) 2007-8 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 +#include +#include +#include + +bool normal_function_called=false; + +void normal_function() +{ + normal_function_called=true; +} + +void test_thread_function_no_arguments() +{ + boost::thread function(normal_function); + function.join(); + BOOST_CHECK(normal_function_called); +} + +int nfoa_res=0; + +void normal_function_one_arg(int i) +{ + nfoa_res=i; +} + +void test_thread_function_one_argument() +{ + boost::thread function(normal_function_one_arg,42); + function.join(); + BOOST_CHECK_EQUAL(42,nfoa_res); +} + +struct callable_no_args +{ + static bool called; + + void operator()() const + { + called=true; + } +}; + +bool callable_no_args::called=false; + +void test_thread_callable_object_no_arguments() +{ + callable_no_args func; + boost::thread callable(func); + callable.join(); + BOOST_CHECK(callable_no_args::called); +} + +struct callable_noncopyable_no_args: + boost::noncopyable +{ + static bool called; + + void operator()() const + { + called=true; + } +}; + +bool callable_noncopyable_no_args::called=false; + +void test_thread_callable_object_ref_no_arguments() +{ + callable_noncopyable_no_args func; + + boost::thread callable(boost::ref(func)); + callable.join(); + BOOST_CHECK(callable_noncopyable_no_args::called); +} + +struct callable_one_arg +{ + static bool called; + static int called_arg; + + void operator()(int arg) const + { + called=true; + called_arg=arg; + } +}; + +bool callable_one_arg::called=false; +int callable_one_arg::called_arg=0; + +void test_thread_callable_object_one_argument() +{ + callable_one_arg func; + boost::thread callable(func,42); + callable.join(); + BOOST_CHECK(callable_one_arg::called); + BOOST_CHECK_EQUAL(callable_one_arg::called_arg,42); +} + +struct callable_multiple_arg +{ + static bool called_two; + static int called_two_arg1; + static double called_two_arg2; + static bool called_three; + static std::string called_three_arg1; + static std::vector called_three_arg2; + static int called_three_arg3; + + void operator()(int arg1,double arg2) const + { + called_two=true; + called_two_arg1=arg1; + called_two_arg2=arg2; + } + void operator()(std::string const& arg1,std::vector const& arg2,int arg3) const + { + called_three=true; + called_three_arg1=arg1; + called_three_arg2=arg2; + called_three_arg3=arg3; + } +}; + +bool callable_multiple_arg::called_two=false; +bool callable_multiple_arg::called_three=false; +int callable_multiple_arg::called_two_arg1; +double callable_multiple_arg::called_two_arg2; +std::string callable_multiple_arg::called_three_arg1; +std::vector callable_multiple_arg::called_three_arg2; +int callable_multiple_arg::called_three_arg3; + +void test_thread_callable_object_multiple_arguments() +{ + std::vector x; + for(unsigned i=0;i<7;++i) + { + x.push_back(i*i); + } + + callable_multiple_arg func; + + boost::thread callable3(func,"hello",x,1.2); + callable3.join(); + BOOST_CHECK(callable_multiple_arg::called_three); + BOOST_CHECK_EQUAL(callable_multiple_arg::called_three_arg1,"hello"); + BOOST_CHECK_EQUAL(callable_multiple_arg::called_three_arg2.size(),x.size()); + for(unsigned j=0;jadd(BOOST_TEST_CASE(test_thread_function_no_arguments)); + test->add(BOOST_TEST_CASE(test_thread_function_one_argument)); + test->add(BOOST_TEST_CASE(test_thread_callable_object_no_arguments)); + test->add(BOOST_TEST_CASE(test_thread_callable_object_ref_no_arguments)); + test->add(BOOST_TEST_CASE(test_thread_callable_object_one_argument)); + test->add(BOOST_TEST_CASE(test_thread_callable_object_multiple_arguments)); + test->add(BOOST_TEST_CASE(test_thread_member_function_no_arguments)); + test->add(BOOST_TEST_CASE(test_thread_member_function_one_argument)); + return test; +} diff --git a/test/test_thread_mf.cpp b/test/test_thread_mf.cpp new file mode 100644 index 00000000..fa1f8a9e --- /dev/null +++ b/test/test_thread_mf.cpp @@ -0,0 +1,136 @@ +// +// Copyright (C) 2008 Peter Dimov +// +// 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 + +struct X +{ + mutable unsigned int hash; + + X(): hash(0) {} + + int f0() { f1(17); return 0; } + int g0() const { g1(17); return 0; } + + int f1(int a1) { hash = (hash * 17041 + a1) % 32768; return 0; } + int g1(int a1) const { hash = (hash * 17041 + a1 * 2) % 32768; return 0; } + + int f2(int a1, int a2) { f1(a1); f1(a2); return 0; } + int g2(int a1, int a2) const { g1(a1); g1(a2); return 0; } + + int f3(int a1, int a2, int a3) { f2(a1, a2); f1(a3); return 0; } + int g3(int a1, int a2, int a3) const { g2(a1, a2); g1(a3); return 0; } + + int f4(int a1, int a2, int a3, int a4) { f3(a1, a2, a3); f1(a4); return 0; } + int g4(int a1, int a2, int a3, int a4) const { g3(a1, a2, a3); g1(a4); return 0; } + + int f5(int a1, int a2, int a3, int a4, int a5) { f4(a1, a2, a3, a4); f1(a5); return 0; } + int g5(int a1, int a2, int a3, int a4, int a5) const { g4(a1, a2, a3, a4); g1(a5); return 0; } + + int f6(int a1, int a2, int a3, int a4, int a5, int a6) { f5(a1, a2, a3, a4, a5); f1(a6); return 0; } + int g6(int a1, int a2, int a3, int a4, int a5, int a6) const { g5(a1, a2, a3, a4, a5); g1(a6); return 0; } + + int f7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) { f6(a1, a2, a3, a4, a5, a6); f1(a7); return 0; } + int g7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) const { g6(a1, a2, a3, a4, a5, a6); g1(a7); return 0; } + + int f8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) { f7(a1, a2, a3, a4, a5, a6, a7); f1(a8); return 0; } + int g8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) const { g7(a1, a2, a3, a4, a5, a6, a7); g1(a8); return 0; } +}; + +int main() +{ + using namespace boost; + + X x; + + // 0 + + thread( &X::f0, &x ).join(); + thread( &X::f0, ref(x) ).join(); + + thread( &X::g0, &x ).join(); + thread( &X::g0, x ).join(); + thread( &X::g0, ref(x) ).join(); + + // 1 + + thread( &X::f1, &x, 1 ).join(); + thread( &X::f1, ref(x), 1 ).join(); + + thread( &X::g1, &x, 1 ).join(); + thread( &X::g1, x, 1 ).join(); + thread( &X::g1, ref(x), 1 ).join(); + + // 2 + + thread( &X::f2, &x, 1, 2 ).join(); + thread( &X::f2, ref(x), 1, 2 ).join(); + + thread( &X::g2, &x, 1, 2 ).join(); + thread( &X::g2, x, 1, 2 ).join(); + thread( &X::g2, ref(x), 1, 2 ).join(); + + // 3 + + thread( &X::f3, &x, 1, 2, 3 ).join(); + thread( &X::f3, ref(x), 1, 2, 3 ).join(); + + thread( &X::g3, &x, 1, 2, 3 ).join(); + thread( &X::g3, x, 1, 2, 3 ).join(); + thread( &X::g3, ref(x), 1, 2, 3 ).join(); + + // 4 + + thread( &X::f4, &x, 1, 2, 3, 4 ).join(); + thread( &X::f4, ref(x), 1, 2, 3, 4 ).join(); + + thread( &X::g4, &x, 1, 2, 3, 4 ).join(); + thread( &X::g4, x, 1, 2, 3, 4 ).join(); + thread( &X::g4, ref(x), 1, 2, 3, 4 ).join(); + + // 5 + + thread( &X::f5, &x, 1, 2, 3, 4, 5 ).join(); + thread( &X::f5, ref(x), 1, 2, 3, 4, 5 ).join(); + + thread( &X::g5, &x, 1, 2, 3, 4, 5 ).join(); + thread( &X::g5, x, 1, 2, 3, 4, 5 ).join(); + thread( &X::g5, ref(x), 1, 2, 3, 4, 5 ).join(); + + // 6 + + thread( &X::f6, &x, 1, 2, 3, 4, 5, 6 ).join(); + thread( &X::f6, ref(x), 1, 2, 3, 4, 5, 6 ).join(); + + thread( &X::g6, &x, 1, 2, 3, 4, 5, 6 ).join(); + thread( &X::g6, x, 1, 2, 3, 4, 5, 6 ).join(); + thread( &X::g6, ref(x), 1, 2, 3, 4, 5, 6 ).join(); + + // 7 + + thread( &X::f7, &x, 1, 2, 3, 4, 5, 6, 7).join(); + thread( &X::f7, ref(x), 1, 2, 3, 4, 5, 6, 7).join(); + + thread( &X::g7, &x, 1, 2, 3, 4, 5, 6, 7).join(); + thread( &X::g7, x, 1, 2, 3, 4, 5, 6, 7).join(); + thread( &X::g7, ref(x), 1, 2, 3, 4, 5, 6, 7).join(); + + // 8 + + thread( &X::f8, &x, 1, 2, 3, 4, 5, 6, 7, 8 ).join(); + thread( &X::f8, ref(x), 1, 2, 3, 4, 5, 6, 7, 8 ).join(); + + thread( &X::g8, &x, 1, 2, 3, 4, 5, 6, 7, 8 ).join(); + thread( &X::g8, x, 1, 2, 3, 4, 5, 6, 7, 8 ).join(); + thread( &X::g8, ref(x), 1, 2, 3, 4, 5, 6, 7, 8 ).join(); + + BOOST_TEST( x.hash == 23558 ); + + return report_errors(); +} diff --git a/test/test_tss.cpp b/test/test_tss.cpp index bbd78d42..8a6545ce 100644 --- a/test/test_tss.cpp +++ b/test/test_tss.cpp @@ -258,11 +258,58 @@ void do_test_tss_does_no_cleanup_after_release() } } +struct dummy_class_tracks_deletions +{ + static unsigned deletions; + + ~dummy_class_tracks_deletions() + { + ++deletions; + } + +}; + +unsigned dummy_class_tracks_deletions::deletions=0; + +boost::thread_specific_ptr tss_with_null_cleanup(NULL); + +void tss_thread_with_null_cleanup(dummy_class_tracks_deletions* delete_tracker) +{ + tss_with_null_cleanup.reset(delete_tracker); +} + +void do_test_tss_does_no_cleanup_with_null_cleanup_function() +{ + dummy_class_tracks_deletions* delete_tracker=new dummy_class_tracks_deletions; + boost::thread t(tss_thread_with_null_cleanup,delete_tracker); + try + { + t.join(); + } + catch(...) + { + t.interrupt(); + t.join(); + throw; + } + + BOOST_CHECK(!dummy_class_tracks_deletions::deletions); + if(!dummy_class_tracks_deletions::deletions) + { + delete delete_tracker; + } +} + void test_tss_does_no_cleanup_after_release() { timed_test(&do_test_tss_does_no_cleanup_after_release, 2); } +void test_tss_does_no_cleanup_with_null_cleanup_function() +{ + timed_test(&do_test_tss_does_no_cleanup_with_null_cleanup_function, 2); +} + boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { boost::unit_test_framework::test_suite* test = @@ -271,6 +318,7 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) test->add(BOOST_TEST_CASE(test_tss)); test->add(BOOST_TEST_CASE(test_tss_with_custom_cleanup)); test->add(BOOST_TEST_CASE(test_tss_does_no_cleanup_after_release)); + test->add(BOOST_TEST_CASE(test_tss_does_no_cleanup_with_null_cleanup_function)); return test; }