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_ref.qbk b/doc/thread_ref.qbk index caadc362..50c05e77 100644 --- a/doc/thread_ref.qbk +++ b/doc/thread_ref.qbk @@ -364,6 +364,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; diff --git a/include/boost/thread/detail/move.hpp b/include/boost/thread/detail/move.hpp index d4732317..48744932 100644 --- a/include/boost/thread/detail/move.hpp +++ b/include/boost/thread/detail/move.hpp @@ -6,6 +6,9 @@ #ifndef BOOST_THREAD_MOVE_HPP #define BOOST_THREAD_MOVE_HPP +#include +#include + namespace boost { namespace detail @@ -14,7 +17,7 @@ namespace boost struct thread_move_t { T& t; - thread_move_t(T& t_): + explicit thread_move_t(T& t_): t(t_) {} @@ -31,6 +34,18 @@ 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; + } } diff --git a/include/boost/thread/locks.hpp b/include/boost/thread/locks.hpp index 71ec5373..b26b4aed 100644 --- a/include/boost/thread/locks.hpp +++ b/include/boost/thread/locks.hpp @@ -62,6 +62,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) { @@ -204,18 +208,6 @@ namespace boost friend class upgrade_lock; }; - template - inline detail::thread_move_t > move(unique_lock & x) - { - return x.move(); - } - - template - inline detail::thread_move_t > move(detail::thread_move_t > x) - { - return x; - } - template class shared_lock { @@ -226,6 +218,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 +248,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 +371,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,6 +381,10 @@ 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) { @@ -415,16 +405,18 @@ namespace boost 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 >() @@ -511,18 +503,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) @@ -595,6 +575,9 @@ namespace boost { typedef unique_lock base; public: + try_lock_wrapper() + {} + explicit try_lock_wrapper(Mutex& m): base(m,try_to_lock) {} diff --git a/include/boost/thread/pthread/mutex.hpp b/include/boost/thread/pthread/mutex.hpp index 9a228817..f99838d6 100644 --- a/include/boost/thread/pthread/mutex.hpp +++ b/include/boost/thread/pthread/mutex.hpp @@ -139,6 +139,13 @@ namespace boost BOOST_ASSERT(!res || res==ETIMEDOUT); return !res; } + + typedef pthread_mutex_t* native_handle_type; + native_handle_type native_handle() + { + return &m; + } + #else void lock() { diff --git a/include/boost/thread/pthread/recursive_mutex.hpp b/include/boost/thread/pthread/recursive_mutex.hpp index b19a1adf..4b50b440 100644 --- a/include/boost/thread/pthread/recursive_mutex.hpp +++ b/include/boost/thread/pthread/recursive_mutex.hpp @@ -76,6 +76,13 @@ 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 detail::try_lock_wrapper scoped_try_lock; }; @@ -171,6 +178,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() { diff --git a/include/boost/thread/pthread/thread.hpp b/include/boost/thread/pthread/thread.hpp index 813ced09..cdfade0e 100644 --- a/include/boost/thread/pthread/thread.hpp +++ b/include/boost/thread/pthread/thread.hpp @@ -222,16 +222,10 @@ namespace boost bool interruption_requested() const; }; - inline detail::thread_move_t move(thread& x) + inline detail::thread_move_t move(detail::thread_move_t t) { - return x.move(); + return t; } - - inline detail::thread_move_t move(detail::thread_move_t x) - { - return x; - } - template struct thread::thread_data >: diff --git a/include/boost/thread/win32/basic_timed_mutex.hpp b/include/boost/thread/win32/basic_timed_mutex.hpp index 207c0920..56b4622a 100644 --- a/include/boost/thread/win32/basic_timed_mutex.hpp +++ b/include/boost/thread/win32/basic_timed_mutex.hpp @@ -21,7 +21,10 @@ namespace boost { 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()); + } } } diff --git a/include/boost/thread/win32/thread.hpp b/include/boost/thread/win32/thread.hpp index 3b043b84..22fa6212 100644 --- a/include/boost/thread/win32/thread.hpp +++ b/include/boost/thread/win32/thread.hpp @@ -281,14 +281,9 @@ namespace boost bool interruption_requested() const; }; - inline detail::thread_move_t move(thread& x) + inline detail::thread_move_t move(detail::thread_move_t t) { - return x.move(); - } - - inline detail::thread_move_t move(detail::thread_move_t x) - { - return x; + return t; } template diff --git a/include/boost/thread/win32/thread_primitives.hpp b/include/boost/thread/win32/thread_primitives.hpp index f8f66b15..3109f142 100644 --- a/include/boost/thread/win32/thread_primitives.hpp +++ b/include/boost/thread/win32/thread_primitives.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #if defined( BOOST_USE_WINDOWS_H ) @@ -277,5 +278,113 @@ namespace boost } } +#if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN) +#if MSC_VER>=1400 +extern "C" unsigned char _interlockedbittestandset(long *a,long b); +extern "C" unsigned char _interlockedbittestandreset(long *a,long b); + +#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); + } + + inline bool interlocked_bit_test_and_reset(long* x,long bit) + { + return _interlockedbittestandreset(x,bit); + } + + } + } +} +#define BOOST_THREAD_BTS_DEFINED +#elif 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 +#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< + +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/test_lock_concept.cpp b/test/test_lock_concept.cpp index e9f0cf0a..6b8b483f 100644 --- a/test/test_lock_concept.cpp +++ b/test/test_lock_concept.cpp @@ -185,11 +185,22 @@ 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()); + }; +}; 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()(); @@ -203,6 +214,7 @@ 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()(); diff --git a/test/test_move_function.cpp b/test/test_move_function.cpp index 153a4cf1..61e08b77 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 +{ + 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::nc src; + user::nc dest=move(src); + BOOST_CHECK(user::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; }