diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 2e8d52b8..88233740 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -236,10 +236,10 @@ rule usage-requirements ( properties * ) } } - if ! vacpp in $(properties) || 11.1 in $(properties) || 12.1.0.1 in $(properties) || 12.1 in $(properties) - { + #if ! vacpp in $(properties) || 11.1 in $(properties) || 12.1.0.1 in $(properties) || 12.1 in $(properties) + #{ result += /boost/chrono//boost_chrono ; - } + #} return $(result) ; } @@ -269,10 +269,10 @@ rule requirements ( properties * ) result += /boost/chrono//boost_chrono ; } - if pgi in $(properties) || vacpp in $(properties) - { + #if pgi in $(properties) || vacpp in $(properties) + #{ result += /boost/atomic//boost_atomic ; - } + #} return $(result) ; } diff --git a/doc/configuration.qbk b/doc/configuration.qbk index 35528858..43f3290a 100644 --- a/doc/configuration.qbk +++ b/doc/configuration.qbk @@ -78,10 +78,18 @@ When `BOOST_THREAD_VERSION>3` && defined BOOST_THREAD_PLATFORM_PTHREAD define ` [endsect] +[section:move Boost.Atomic] -[section:thread_eq `boost::thread::oprator==` deprecated] +Boost.Thread uses by default an Boost.Atomic in POSIX platforms to implement call_once.. -The following nested typedefs are deprecated: +Define `BOOST_THREAD_USES_ATOMIC ` if you want to use Boost.Atomic. +Define `BOOST_THREAD_DONT_USE_ATOMIC ` if you don't want to use Boost.Atomic or if it is not supported in your platform. + +[endsect] + +[section:thread_eq `boost::thread::operator==` deprecated] + +The following operators are deprecated: * `boost::thread::oprator==` * `boost::thread::oprator!=` diff --git a/doc/external_locking.qbk b/doc/external_locking.qbk index 9f78d68c..c9e722c6 100644 --- a/doc/external_locking.qbk +++ b/doc/external_locking.qbk @@ -217,7 +217,7 @@ Silence can be sometimes louder than words-what's forbidden to do with a `strict * You can create a `strict_lock` only starting from a valid T object. Notice that there is no other way you can create a `strict_lock`. BankAccount myAccount("John Doe", "123-45-6789"); - strict_locerk myLock(myAccount); // ok + strict_lock myLock(myAccount); // ok * You cannot copy `strict_lock`s to one another. In particular, you cannot pass `strict_lock`s by value to functions or have them returned by functions: @@ -468,7 +468,7 @@ Now imagine that the AccountManager function needs to take a `unique_lock` in or We need a way to transfer the ownership from the `unique_lock` to a `strict_lock` the time we are working with `savingsAcct_` and then restore the ownership on `unique_lock`. void AccountManager::AMoreComplicatedChecking2Savings(int amount) { - unique_lock guard(*this, defer_lock); + unique_lock guard1(*this, defer_lock); if (some_condition()) { guard1.lock(); } diff --git a/doc/mutex_concepts.qbk b/doc/mutex_concepts.qbk index b9fbe2b1..a74b53ab 100644 --- a/doc/mutex_concepts.qbk +++ b/doc/mutex_concepts.qbk @@ -1273,7 +1273,7 @@ The following classes are models of `StrictLock`: explicit operator bool() const noexcept; bool owns_lock() const noexcept; - Lockable* mutex() const noexcept; + mutex_type* mutex() const noexcept; #if defined BOOST_THREAD_USE_DATE_TIME || defined BOOST_THREAD_DONT_USE_CHRONO unique_lock(Lockable& m_,system_time const& target_time); @@ -1535,7 +1535,7 @@ object associated with `*this`.]] [endsect] -[section:mutex `Lockable* mutex() const`] +[section:mutex `Lockable* mutex() const noexcept`] [variablelist @@ -1907,7 +1907,7 @@ state (including the destructor) must be called by the same thread that acquired [endsect] -[section:upgrade_to_unique_lock Class template `upgrade_to_unique_lock`] +[section:upgrade_to_unique_lock Class template `upgrade_to_unique_lock` -- EXTENSION] // #include // #include @@ -1930,6 +1930,8 @@ state (including the destructor) must be called by the same thread that acquired explicit operator bool() const; bool owns_lock() const; + mutex_type* mutex() const; + }; __upgrade_to_unique_lock__ allows for a temporary upgrade of an __upgrade_lock__ to exclusive ownership. When constructed with a @@ -1939,7 +1941,7 @@ __lockable_concept_type__ is downgraded back to ['upgrade ownership]. [endsect] -[section:scoped_try_lock Mutex-specific class `scoped_try_lock`] +[section:scoped_try_lock Mutex-specific class `scoped_try_lock` -- DEPRECATED] class MutexType::scoped_try_lock { diff --git a/include/boost/thread/barrier.hpp b/include/boost/thread/barrier.hpp index 88378ab6..18508221 100644 --- a/include/boost/thread/barrier.hpp +++ b/include/boost/thread/barrier.hpp @@ -57,7 +57,8 @@ namespace boost struct void_functor_barrier_reseter { unsigned int size_; - void_completion_function fct_;template + void_completion_function fct_; + template #ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL void_functor_barrier_reseter(unsigned int size, BOOST_THREAD_RV_REF(F) funct) : size_(size), fct_(boost::move(funct)) @@ -90,7 +91,7 @@ namespace boost } class barrier { - static inline unsigned int check(unsigned int count) + static inline unsigned int check_counter(unsigned int count) { if (count == 0) boost::throw_exception( thread_exception(system::errc::invalid_argument, "barrier constructor: count cannot be zero.")); @@ -104,7 +105,7 @@ namespace boost BOOST_THREAD_NO_COPYABLE( barrier) explicit barrier(unsigned int count) : - m_count(check(count)), m_generation(0), fct_(thread_detail::default_barrier_reseter(count)) + m_count(check_counter(count)), m_generation(0), fct_(thread_detail::default_barrier_reseter(count)) { } @@ -120,7 +121,7 @@ namespace boost typename is_void::type>::type, dummy* >::type=0 ) - : m_count(check(count)), + : m_count(check_counter(count)), m_generation(0), fct_(thread_detail::void_functor_barrier_reseter(count, #ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL @@ -145,7 +146,7 @@ namespace boost typename is_same::type, unsigned int>::type, dummy* >::type=0 ) - : m_count(check(count)), + : m_count(check_counter(count)), m_generation(0), fct_( #ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL @@ -158,7 +159,7 @@ namespace boost } barrier(unsigned int count, void(*funct)()) : - m_count(check(count)), m_generation(0), + m_count(check_counter(count)), m_generation(0), fct_(funct ? thread_detail::size_completion_function(thread_detail::void_fct_ptr_barrier_reseter(count, funct)) : thread_detail::size_completion_function(thread_detail::default_barrier_reseter(count)) @@ -166,7 +167,7 @@ namespace boost { } barrier(unsigned int count, unsigned int(*funct)()) : - m_count(check(count)), m_generation(0), + m_count(check_counter(count)), m_generation(0), fct_(funct ? thread_detail::size_completion_function(funct) : thread_detail::size_completion_function(thread_detail::default_barrier_reseter(count)) diff --git a/include/boost/thread/lock_types.hpp b/include/boost/thread/lock_types.hpp index 2d40d227..dcbdc90e 100644 --- a/include/boost/thread/lock_types.hpp +++ b/include/boost/thread/lock_types.hpp @@ -1112,6 +1112,10 @@ namespace boost { return exclusive.owns_lock(); } + Mutex* mutex() const BOOST_NOEXCEPT + { + return exclusive.mutex(); + } }; BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) upgrade_to_unique_lock BOOST_THREAD_DCL_MOVABLE_END @@ -1187,7 +1191,7 @@ private unique_lock { return base::owns_lock(); } - Mutex* mutex() const + Mutex* mutex() const BOOST_NOEXCEPT { return base::mutex(); } diff --git a/include/boost/thread/pthread/condition_variable.hpp b/include/boost/thread/pthread/condition_variable.hpp index abebeb7f..b1b76b01 100644 --- a/include/boost/thread/pthread/condition_variable.hpp +++ b/include/boost/thread/pthread/condition_variable.hpp @@ -200,15 +200,15 @@ namespace boost #if defined BOOST_THREAD_USES_DATETIME template - bool timed_wait(lock_type& m,boost::system_time const& wait_until) + bool timed_wait(lock_type& m,boost::system_time const& abs_time) { - struct timespec const timeout=detail::to_timespec(wait_until); + struct timespec const timeout=detail::to_timespec(abs_time); return do_wait_until(m, timeout); } template - bool timed_wait(lock_type& m,xtime const& wait_until) + bool timed_wait(lock_type& m,xtime const& abs_time) { - return timed_wait(m,system_time(wait_until)); + return timed_wait(m,system_time(abs_time)); } template @@ -218,20 +218,20 @@ namespace boost } template - bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred) + bool timed_wait(lock_type& m,boost::system_time const& abs_time, predicate_type pred) { while (!pred()) { - if(!timed_wait(m, wait_until)) + if(!timed_wait(m, abs_time)) return pred(); } return true; } template - bool timed_wait(lock_type& m,xtime const& wait_until,predicate_type pred) + bool timed_wait(lock_type& m,xtime const& abs_time, predicate_type pred) { - return timed_wait(m,system_time(wait_until),pred); + return timed_wait(m,system_time(abs_time),pred); } template diff --git a/include/boost/thread/pthread/condition_variable_fwd.hpp b/include/boost/thread/pthread/condition_variable_fwd.hpp index e567fc87..e18030fd 100644 --- a/include/boost/thread/pthread/condition_variable_fwd.hpp +++ b/include/boost/thread/pthread/condition_variable_fwd.hpp @@ -98,21 +98,21 @@ namespace boost #if defined BOOST_THREAD_USES_DATETIME inline bool timed_wait( unique_lock& m, - boost::system_time const& wait_until) + boost::system_time const& abs_time) { #if defined BOOST_THREAD_WAIT_BUG - struct timespec const timeout=detail::to_timespec(wait_until + BOOST_THREAD_WAIT_BUG); + struct timespec const timeout=detail::to_timespec(abs_time + BOOST_THREAD_WAIT_BUG); return do_wait_until(m, timeout); #else - struct timespec const timeout=detail::to_timespec(wait_until); + struct timespec const timeout=detail::to_timespec(abs_time); return do_wait_until(m, timeout); #endif } bool timed_wait( unique_lock& m, - xtime const& wait_until) + xtime const& abs_time) { - return timed_wait(m,system_time(wait_until)); + return timed_wait(m,system_time(abs_time)); } template @@ -126,11 +126,11 @@ namespace boost template bool timed_wait( unique_lock& m, - boost::system_time const& wait_until,predicate_type pred) + boost::system_time const& abs_time,predicate_type pred) { while (!pred()) { - if(!timed_wait(m, wait_until)) + if(!timed_wait(m, abs_time)) return pred(); } return true; @@ -139,9 +139,9 @@ namespace boost template bool timed_wait( unique_lock& m, - xtime const& wait_until,predicate_type pred) + xtime const& abs_time,predicate_type pred) { - return timed_wait(m,system_time(wait_until),pred); + return timed_wait(m,system_time(abs_time),pred); } template diff --git a/include/boost/thread/synchronized_value.hpp b/include/boost/thread/synchronized_value.hpp index bff5a9d7..18ca4d67 100644 --- a/include/boost/thread/synchronized_value.hpp +++ b/include/boost/thread/synchronized_value.hpp @@ -26,10 +26,12 @@ //#endif #if ! defined(BOOST_THREAD_NO_SYNCHRONIZE) -#include // todo change to once Boost.Tuple or Boost.Fusion provides Move semantics. +#include // todo change to once Boost.Tuple or Boost.Fusion provides Move semantics on C++98 compilers. #include #endif +#include + #include namespace boost @@ -593,8 +595,6 @@ namespace boost boost::swap(value_, rhs); } - - /** * Essentially calling a method obj->foo(x, y, z) calls the method foo(x, y, z) inside a critical section as * long-lived as the call itself. @@ -613,14 +613,81 @@ namespace boost return BOOST_THREAD_MAKE_RV_REF((const_strict_lock_ptr(value_, mtx_))); } + /** + * Call function on a locked block. + * + * @requires fct(value_) is well formed. + * + * Example + * void fun(synchronized_value> & v) { + * v ( [](vector> & vec) + * { + * vec.push_back(42); + * assert(vec.back() == 42); + * } ); + * } + */ + template + inline + typename boost::result_of::type + operator()(BOOST_THREAD_RV_REF(F) fct) + { + strict_lock lk(mtx_); + return fct(value_); + } + template + inline + typename boost::result_of::type + operator()(BOOST_THREAD_RV_REF(F) fct) const + { + strict_lock lk(mtx_); + return fct(value_); + } + + +#if defined BOOST_NO_CXX11_RVALUE_REFERENCES + template + inline + typename boost::result_of::type + operator()(F const & fct) + { + strict_lock lk(mtx_); + return fct(value_); + } + template + inline + typename boost::result_of::type + operator()(F const & fct) const + { + strict_lock lk(mtx_); + return fct(value_); + } + + template + inline + R operator()(R(*fct)(value_type&)) + { + strict_lock lk(mtx_); + return fct(value_); + } + template + inline + R operator()(R(*fct)(value_type const&)) const + { + strict_lock lk(mtx_); + return fct(value_); + } +#endif + + /** * The synchronize() factory make easier to lock on a scope. * As discussed, operator-> can only lock over the duration of a call, so it is insufficient for complex operations. * With synchronize() you get to lock the object in a scoped and to directly access the object inside that scope. * * Example - * void fun(synchronized_value> & vec) { - * auto&& vec=vec.synchronize(); + * void fun(synchronized_value> & v) { + * auto&& vec=v.synchronize(); * vec.push_back(42); * assert(vec.back() == 42); * } @@ -880,9 +947,9 @@ namespace boost //Hash support - template struct hash; - template - struct hash >; +// template struct hash; +// template +// struct hash >; // Comparison with T template diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 0904e3de..4ba5efde 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -768,6 +768,7 @@ rule thread-compile ( sources : reqs * : name ) [ thread-run2-noit ./sync/mutual_exclusion/synchronized_value/swap_pass.cpp : synchronized_value__swap_p ] [ thread-run2-noit ./sync/mutual_exclusion/synchronized_value/swap_T_pass.cpp : synchronized_value__swap_T_p ] [ thread-run2-noit ./sync/mutual_exclusion/synchronized_value/synchronize_pass.cpp : synchronized_value__synchronize_p ] + [ thread-run2-noit ./sync/mutual_exclusion/synchronized_value/call_pass.cpp : synchronized_value__call_p ] ; @@ -789,7 +790,8 @@ rule thread-compile ( sources : reqs * : name ) #[ thread-run test_8586.cpp ] #[ thread-run test_8596.cpp ] #[ thread-run test_8600.cpp ] - #[ thread-run2-noit ./sync/mutual_exclusion/sync_bounded_queue/multi_thread_pass.cpp : sync_bounded_queue__multi_thread_p ] + #[ thread-run test_8943.cpp ] + #[ thread-run test_8960.cpp ] ; diff --git a/test/sync/mutual_exclusion/synchronized_value/call_pass.cpp b/test/sync/mutual_exclusion/synchronized_value/call_pass.cpp new file mode 100644 index 00000000..13ea1a2f --- /dev/null +++ b/test/sync/mutual_exclusion/synchronized_value/call_pass.cpp @@ -0,0 +1,144 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// 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) + +// + +// class synchronized_value + +// template +// inline typename boost::result_of::type +// operator()(BOOST_THREAD_RV_REF(F) fct); +// template +// inline typename boost::result_of::type +// operator()(BOOST_THREAD_RV_REF(F) fct) const; + +#include +#if ! defined BOOST_NO_CXX11_DECLTYPE +#define BOOST_RESULT_OF_USE_DECLTYPE +#endif + +#define BOOST_THREAD_VERSION 4 + +#include + +#include + +struct S { + int f() const {return 1;} + int g() {return 1;} +}; + +void c(S const& s) +{ + BOOST_TEST(s.f()==1); +} + +void nc(S & s) +{ + BOOST_TEST(s.f()==1); + BOOST_TEST(s.g()==1); +} + +struct cfctr { + typedef void result_type; + void operator()(S const& s) const { + BOOST_TEST(s.f()==1); + } +}; +struct ncfctr { + typedef void result_type; + void operator()(S& s) const { + BOOST_TEST(s.f()==1); + BOOST_TEST(s.g()==1); + } +}; + +struct cfctr3 { + typedef void result_type; + BOOST_THREAD_MOVABLE_ONLY(cfctr3) + cfctr3() + {} + cfctr3(BOOST_THREAD_RV_REF(cfctr3)) + {} + void operator()(S const& s) const { + BOOST_TEST(s.f()==1); + } +}; +struct ncfctr3 { + typedef void result_type; + BOOST_THREAD_MOVABLE_ONLY(ncfctr3) + ncfctr3() + {} + ncfctr3(BOOST_THREAD_RV_REF(ncfctr3)) + {} + void operator()(S& s) const { + BOOST_TEST(s.f()==1); + BOOST_TEST(s.g()==1); + } +}; + +cfctr3 make_cfctr3() { + return BOOST_THREAD_MAKE_RV_REF(cfctr3()); +} + +ncfctr3 make_ncfctr3() { + return BOOST_THREAD_MAKE_RV_REF(ncfctr3()); +} + +int main() +{ + { + boost::synchronized_value v; + v(&nc); + //v(&c); + } + { + const boost::synchronized_value v; + v(&c); + } + { + boost::synchronized_value v; + v(ncfctr()); + } + { + const boost::synchronized_value v; + v(cfctr()); + } + { + boost::synchronized_value v; + ncfctr fct; + v(fct); + } + { + const boost::synchronized_value v; + cfctr fct; + v(fct); + } + { + boost::synchronized_value v; + v(make_ncfctr3()); + } + { + const boost::synchronized_value v; + v(make_cfctr3()); + } +#if ! defined BOOST_NO_CXX11_LAMBDAS + { + boost::synchronized_value v; + v([](S& s) { + BOOST_TEST(s.f()==1); + BOOST_TEST(s.g()==1); + }); + } + { + const boost::synchronized_value v; + v([](S const& s) { + BOOST_TEST(s.f()==1); + }); + } +#endif + return boost::report_errors(); +} +