Chris@16: // (C) Copyright 2010 Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk Chris@16: // (C) Copyright 2012 Vicente J. Botet Escriba Chris@16: // Distributed under the Boost Software License, Version 1.0. (See Chris@16: // accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: Chris@16: #ifndef BOOST_THREAD_SYNCHRONIZED_VALUE_HPP Chris@16: #define BOOST_THREAD_SYNCHRONIZED_VALUE_HPP Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: #include Chris@16: //#include Chris@16: //#include Chris@16: //#if ! defined BOOST_NO_CXX11_HDR_TYPE_TRAITS Chris@16: //#include Chris@16: //#endif Chris@16: Chris@16: #if ! defined(BOOST_THREAD_NO_SYNCHRONIZE) Chris@16: #include // todo change to once Boost.Tuple or Boost.Fusion provides Move semantics on C++98 compilers. Chris@16: #include Chris@16: #endif Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost Chris@16: { Chris@16: Chris@16: /** Chris@16: * strict lock providing a const pointer access to the synchronized value type. Chris@16: * Chris@16: * @param T the value type. Chris@16: * @param Lockable the mutex type protecting the value type. Chris@16: */ Chris@16: template Chris@16: class const_strict_lock_ptr Chris@16: { Chris@16: public: Chris@16: typedef T value_type; Chris@16: typedef Lockable mutex_type; Chris@16: protected: Chris@16: Chris@16: // this should be a strict_lock, but unique_lock is needed to be able to return it. Chris@16: boost::unique_lock lk_; Chris@16: T const& value_; Chris@16: Chris@16: public: Chris@16: BOOST_THREAD_MOVABLE_ONLY( const_strict_lock_ptr ) Chris@16: Chris@16: /** Chris@16: * @param value constant reference of the value to protect. Chris@16: * @param mtx reference to the mutex used to protect the value. Chris@16: * @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value. Chris@16: */ Chris@16: const_strict_lock_ptr(T const& val, Lockable & mtx) : Chris@16: lk_(mtx), value_(val) Chris@16: { Chris@16: } Chris@16: const_strict_lock_ptr(T const& val, Lockable & mtx, adopt_lock_t tag) BOOST_NOEXCEPT : Chris@16: lk_(mtx, tag), value_(val) Chris@16: { Chris@16: } Chris@16: /** Chris@16: * Move constructor. Chris@16: * @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other. Chris@16: */ Chris@16: const_strict_lock_ptr(BOOST_THREAD_RV_REF(const_strict_lock_ptr) other) BOOST_NOEXCEPT Chris@16: : lk_(boost::move(BOOST_THREAD_RV(other).lk_)),value_(BOOST_THREAD_RV(other).value_) Chris@16: { Chris@16: } Chris@16: Chris@16: ~const_strict_lock_ptr() Chris@16: { Chris@16: } Chris@16: Chris@16: /** Chris@16: * @return a constant pointer to the protected value Chris@16: */ Chris@16: const T* operator->() const Chris@16: { Chris@16: return &value_; Chris@16: } Chris@16: Chris@16: /** Chris@16: * @return a constant reference to the protected value Chris@16: */ Chris@16: const T& operator*() const Chris@16: { Chris@16: return value_; Chris@16: } Chris@16: Chris@16: }; Chris@16: Chris@16: /** Chris@16: * strict lock providing a pointer access to the synchronized value type. Chris@16: * Chris@16: * @param T the value type. Chris@16: * @param Lockable the mutex type protecting the value type. Chris@16: */ Chris@16: template Chris@16: class strict_lock_ptr : public const_strict_lock_ptr Chris@16: { Chris@16: typedef const_strict_lock_ptr base_type; Chris@16: public: Chris@16: BOOST_THREAD_MOVABLE_ONLY( strict_lock_ptr ) Chris@16: Chris@16: /** Chris@16: * @param value reference of the value to protect. Chris@16: * @param mtx reference to the mutex used to protect the value. Chris@16: * @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value. Chris@16: */ Chris@16: strict_lock_ptr(T & val, Lockable & mtx) : Chris@16: base_type(val, mtx) Chris@16: { Chris@16: } Chris@16: strict_lock_ptr(T & val, Lockable & mtx, adopt_lock_t tag) : Chris@16: base_type(val, mtx, tag) Chris@16: { Chris@16: } Chris@16: Chris@16: /** Chris@16: * Move constructor. Chris@16: * @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other. Chris@16: */ Chris@16: strict_lock_ptr(BOOST_THREAD_RV_REF(strict_lock_ptr) other) Chris@16: : base_type(boost::move(static_cast(other))) Chris@16: { Chris@16: } Chris@16: Chris@16: ~strict_lock_ptr() Chris@16: { Chris@16: } Chris@16: Chris@16: /** Chris@16: * @return a pointer to the protected value Chris@16: */ Chris@16: T* operator->() Chris@16: { Chris@16: return const_cast(&this->value_); Chris@16: } Chris@16: Chris@16: /** Chris@16: * @return a reference to the protected value Chris@16: */ Chris@16: T& operator*() Chris@16: { Chris@16: return const_cast(this->value_); Chris@16: } Chris@16: Chris@16: }; Chris@16: Chris@16: template Chris@16: struct synchronized_value_strict_lock_ptr Chris@16: { Chris@16: typedef strict_lock_ptr type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct synchronized_value_strict_lock_ptr Chris@16: { Chris@16: typedef const_strict_lock_ptr type; Chris@16: }; Chris@16: /** Chris@16: * unique_lock providing a const pointer access to the synchronized value type. Chris@16: * Chris@16: * An object of type const_unique_lock_ptr is a unique_lock that provides a const pointer access to the synchronized value type. Chris@16: * As unique_lock controls the ownership of a lockable object within a scope. Chris@16: * Ownership of the lockable object may be acquired at construction or after construction, Chris@16: * and may be transferred, after acquisition, to another const_unique_lock_ptr object. Chris@16: * Objects of type const_unique_lock_ptr are not copyable but are movable. Chris@16: * The behavior of a program is undefined if the mutex and the value type Chris@16: * pointed do not exist for the entire remaining lifetime of the const_unique_lock_ptr object. Chris@16: * The supplied Mutex type shall meet the BasicLockable requirements. Chris@16: * Chris@16: * @note const_unique_lock_ptr meets the Lockable requirements. Chris@16: * If Lockable meets the TimedLockable requirements, const_unique_lock_ptr Chris@16: * also meets the TimedLockable requirements. Chris@16: * Chris@16: * @param T the value type. Chris@16: * @param Lockable the mutex type protecting the value type. Chris@16: */ Chris@16: template Chris@16: class const_unique_lock_ptr : public unique_lock Chris@16: { Chris@16: typedef unique_lock base_type; Chris@16: public: Chris@16: typedef T value_type; Chris@16: typedef Lockable mutex_type; Chris@16: protected: Chris@16: T const& value_; Chris@16: Chris@16: public: Chris@16: BOOST_THREAD_MOVABLE_ONLY(const_unique_lock_ptr) Chris@16: Chris@16: /** Chris@16: * @param value reference of the value to protect. Chris@16: * @param mtx reference to the mutex used to protect the value. Chris@16: * Chris@16: * @requires If mutex_type is not a recursive mutex the calling thread does not own the mutex. Chris@16: * Chris@16: * @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value. Chris@16: */ Chris@16: const_unique_lock_ptr(T const& val, Lockable & mtx) Chris@16: : base_type(mtx), value_(val) Chris@16: { Chris@16: } Chris@16: /** Chris@16: * @param value reference of the value to protect. Chris@16: * @param mtx reference to the mutex used to protect the value. Chris@16: * @param tag of type adopt_lock_t used to differentiate the constructor. Chris@16: * @requires The calling thread own the mutex. Chris@16: * @effects stores a reference to it and to the value type @c value taking ownership. Chris@16: */ Chris@16: const_unique_lock_ptr(T const& val, Lockable & mtx, adopt_lock_t) BOOST_NOEXCEPT Chris@16: : base_type(mtx, adopt_lock), value_(val) Chris@16: { Chris@16: } Chris@16: /** Chris@16: * @param value reference of the value to protect. Chris@16: * @param mtx reference to the mutex used to protect the value. Chris@16: * @param tag of type defer_lock_t used to differentiate the constructor. Chris@16: * @effects stores a reference to it and to the value type @c value c. Chris@16: */ Chris@16: const_unique_lock_ptr(T const& val, Lockable & mtx, defer_lock_t) BOOST_NOEXCEPT Chris@16: : base_type(mtx, defer_lock), value_(val) Chris@16: { Chris@16: } Chris@16: /** Chris@16: * @param value reference of the value to protect. Chris@16: * @param mtx reference to the mutex used to protect the value. Chris@16: * @param tag of type try_to_lock_t used to differentiate the constructor. Chris@16: * @requires If mutex_type is not a recursive mutex the calling thread does not own the mutex. Chris@16: * @effects try to lock the mutex @c mtx, stores a reference to it and to the value type @c value. Chris@16: */ Chris@16: const_unique_lock_ptr(T const& val, Lockable & mtx, try_to_lock_t) BOOST_NOEXCEPT Chris@16: : base_type(mtx, try_to_lock), value_(val) Chris@16: { Chris@16: } Chris@16: /** Chris@16: * Move constructor. Chris@16: * @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other. Chris@16: */ Chris@16: const_unique_lock_ptr(BOOST_THREAD_RV_REF(const_unique_lock_ptr) other) BOOST_NOEXCEPT Chris@16: : base_type(boost::move(static_cast(other))), value_(BOOST_THREAD_RV(other).value_) Chris@16: { Chris@16: } Chris@16: Chris@16: /** Chris@16: * @effects If owns calls unlock() on the owned mutex. Chris@16: */ Chris@16: ~const_unique_lock_ptr() Chris@16: { Chris@16: } Chris@16: Chris@16: /** Chris@16: * @return a constant pointer to the protected value Chris@16: */ Chris@16: const T* operator->() const Chris@16: { Chris@16: BOOST_ASSERT (this->owns_lock()); Chris@16: return &value_; Chris@16: } Chris@16: Chris@16: /** Chris@16: * @return a constant reference to the protected value Chris@16: */ Chris@16: const T& operator*() const Chris@16: { Chris@16: BOOST_ASSERT (this->owns_lock()); Chris@16: return value_; Chris@16: } Chris@16: Chris@16: }; Chris@16: Chris@16: /** Chris@16: * unique lock providing a pointer access to the synchronized value type. Chris@16: * Chris@16: * @param T the value type. Chris@16: * @param Lockable the mutex type protecting the value type. Chris@16: */ Chris@16: template Chris@16: class unique_lock_ptr : public const_unique_lock_ptr Chris@16: { Chris@16: typedef const_unique_lock_ptr base_type; Chris@16: public: Chris@16: typedef T value_type; Chris@16: typedef Lockable mutex_type; Chris@16: Chris@16: BOOST_THREAD_MOVABLE_ONLY(unique_lock_ptr) Chris@16: Chris@16: /** Chris@16: * @param value reference of the value to protect. Chris@16: * @param mtx reference to the mutex used to protect the value. Chris@16: * @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value. Chris@16: */ Chris@16: unique_lock_ptr(T & val, Lockable & mtx) Chris@16: : base_type(val, mtx) Chris@16: { Chris@16: } Chris@16: /** Chris@16: * @param value reference of the value to protect. Chris@16: * @param mtx reference to the mutex used to protect the value. Chris@16: * @param tag of type adopt_lock_t used to differentiate the constructor. Chris@16: * @effects stores a reference to it and to the value type @c value taking ownership. Chris@16: */ Chris@16: unique_lock_ptr(T & value, Lockable & mtx, adopt_lock_t) BOOST_NOEXCEPT Chris@16: : base_type(value, mtx, adopt_lock) Chris@16: { Chris@16: } Chris@16: /** Chris@16: * @param value reference of the value to protect. Chris@16: * @param mtx reference to the mutex used to protect the value. Chris@16: * @param tag of type defer_lock_t used to differentiate the constructor. Chris@16: * @effects stores a reference to it and to the value type @c value c. Chris@16: */ Chris@16: unique_lock_ptr(T & value, Lockable & mtx, defer_lock_t) BOOST_NOEXCEPT Chris@16: : base_type(value, mtx, defer_lock) Chris@16: { Chris@16: } Chris@16: /** Chris@16: * @param value reference of the value to protect. Chris@16: * @param mtx reference to the mutex used to protect the value. Chris@16: * @param tag of type try_to_lock_t used to differentiate the constructor. Chris@16: * @effects try to lock the mutex @c mtx, stores a reference to it and to the value type @c value. Chris@16: */ Chris@16: unique_lock_ptr(T & value, Lockable & mtx, try_to_lock_t) BOOST_NOEXCEPT Chris@16: : base_type(value, mtx, try_to_lock) Chris@16: { Chris@16: } Chris@16: /** Chris@16: * Move constructor. Chris@16: * @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other. Chris@16: */ Chris@16: unique_lock_ptr(BOOST_THREAD_RV_REF(unique_lock_ptr) other) BOOST_NOEXCEPT Chris@16: : base_type(boost::move(static_cast(other))) Chris@16: { Chris@16: } Chris@16: Chris@16: ~unique_lock_ptr() Chris@16: { Chris@16: } Chris@16: Chris@16: /** Chris@16: * @return a pointer to the protected value Chris@16: */ Chris@16: T* operator->() Chris@16: { Chris@16: BOOST_ASSERT (this->owns_lock()); Chris@16: return const_cast(&this->value_); Chris@16: } Chris@16: Chris@16: /** Chris@16: * @return a reference to the protected value Chris@16: */ Chris@16: T& operator*() Chris@16: { Chris@16: BOOST_ASSERT (this->owns_lock()); Chris@16: return const_cast(this->value_); Chris@16: } Chris@16: Chris@16: Chris@16: }; Chris@16: Chris@16: template Chris@16: struct synchronized_value_unique_lock_ptr Chris@16: { Chris@16: typedef unique_lock_ptr type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct synchronized_value_unique_lock_ptr Chris@16: { Chris@16: typedef const_unique_lock_ptr type; Chris@16: }; Chris@16: /** Chris@16: * cloaks a value type and the mutex used to protect it together. Chris@16: * @param T the value type. Chris@16: * @param Lockable the mutex type protecting the value type. Chris@16: */ Chris@16: template Chris@16: class synchronized_value Chris@16: { Chris@16: Chris@16: #if ! defined(BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS) Chris@16: #if ! defined BOOST_NO_CXX11_VARIADIC_TEMPLATES Chris@16: template Chris@16: friend std::tuple::type ...> synchronize(SV& ...sv); Chris@16: #else Chris@16: template Chris@16: friend std::tuple< Chris@16: typename synchronized_value_strict_lock_ptr::type, Chris@16: typename synchronized_value_strict_lock_ptr::type Chris@16: > Chris@16: synchronize(SV1& sv1, SV2& sv2); Chris@16: template Chris@16: friend std::tuple< Chris@16: typename synchronized_value_strict_lock_ptr::type, Chris@16: typename synchronized_value_strict_lock_ptr::type, Chris@16: typename synchronized_value_strict_lock_ptr::type Chris@16: > Chris@16: synchronize(SV1& sv1, SV2& sv2, SV3& sv3); Chris@16: #endif Chris@16: #endif Chris@16: Chris@16: public: Chris@16: typedef T value_type; Chris@16: typedef Lockable mutex_type; Chris@16: private: Chris@16: T value_; Chris@16: mutable mutex_type mtx_; Chris@16: public: Chris@16: // construction/destruction Chris@16: /** Chris@16: * Default constructor. Chris@16: * Chris@16: * @Requires: T is DefaultConstructible Chris@16: */ Chris@16: synchronized_value() Chris@16: //BOOST_NOEXCEPT_IF(is_nothrow_default_constructible::value) Chris@16: : value_() Chris@16: { Chris@16: } Chris@16: Chris@16: /** Chris@16: * Constructor from copy constructible value. Chris@16: * Chris@16: * Requires: T is CopyConstructible Chris@16: */ Chris@16: synchronized_value(T const& other) Chris@16: //BOOST_NOEXCEPT_IF(is_nothrow_copy_constructible::value) Chris@16: : value_(other) Chris@16: { Chris@16: } Chris@16: Chris@16: /** Chris@16: * Move Constructor. Chris@16: * Chris@16: * Requires: T is CopyMovable Chris@16: */ Chris@16: synchronized_value(BOOST_THREAD_RV_REF(T) other) Chris@16: //BOOST_NOEXCEPT_IF(is_nothrow_move_constructible::value) Chris@16: : value_(boost::move(other)) Chris@16: { Chris@16: } Chris@16: Chris@16: /** Chris@16: * Constructor from value type. Chris@16: * Chris@16: * Requires: T is DefaultConstructible and Assignable Chris@16: * Effects: Assigns the value on a scope protected by the mutex of the rhs. The mutex is not copied. Chris@16: */ Chris@16: synchronized_value(synchronized_value const& rhs) Chris@16: { Chris@16: strict_lock lk(rhs.mtx_); Chris@16: value_ = rhs.value_; Chris@16: } Chris@16: Chris@16: /** Chris@16: * Move Constructor from movable value type Chris@16: * Chris@16: */ Chris@16: synchronized_value(BOOST_THREAD_RV_REF(synchronized_value) other) Chris@16: { Chris@101: strict_lock lk(BOOST_THREAD_RV(other).mtx_); Chris@101: value_= boost::move(BOOST_THREAD_RV(other).value_); Chris@16: } Chris@16: Chris@16: // mutation Chris@16: /** Chris@16: * Assignment operator. Chris@16: * Chris@16: * Effects: Copies the underlying value on a scope protected by the two mutexes. Chris@16: * The mutex is not copied. The locks are acquired using lock, so deadlock is avoided. Chris@16: * For example, there is no problem if one thread assigns a = b and the other assigns b = a. Chris@16: * Chris@16: * Return: *this Chris@16: */ Chris@16: Chris@16: synchronized_value& operator=(synchronized_value const& rhs) Chris@16: { Chris@16: if(&rhs != this) Chris@16: { Chris@16: // auto _ = make_unique_locks(mtx_, rhs.mtx_); Chris@16: unique_lock lk1(mtx_, defer_lock); Chris@16: unique_lock lk2(rhs.mtx_, defer_lock); Chris@16: lock(lk1,lk2); Chris@16: Chris@16: value_ = rhs.value_; Chris@16: } Chris@16: return *this; Chris@16: } Chris@16: /** Chris@16: * Assignment operator from a T const&. Chris@16: * Effects: The operator copies the value on a scope protected by the mutex. Chris@16: * Return: *this Chris@16: */ Chris@16: synchronized_value& operator=(value_type const& val) Chris@16: { Chris@16: { Chris@16: strict_lock lk(mtx_); Chris@16: value_ = val; Chris@16: } Chris@16: return *this; Chris@16: } Chris@16: Chris@16: //observers Chris@16: /** Chris@16: * Explicit conversion to value type. Chris@16: * Chris@16: * Requires: T is CopyConstructible Chris@16: * Return: A copy of the protected value obtained on a scope protected by the mutex. Chris@16: * Chris@16: */ Chris@16: T get() const Chris@16: { Chris@16: strict_lock lk(mtx_); Chris@16: return value_; Chris@16: } Chris@16: /** Chris@16: * Explicit conversion to value type. Chris@16: * Chris@16: * Requires: T is CopyConstructible Chris@16: * Return: A copy of the protected value obtained on a scope protected by the mutex. Chris@16: * Chris@16: */ Chris@16: #if ! defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) Chris@16: explicit operator T() const Chris@16: { Chris@16: return get(); Chris@16: } Chris@16: #endif Chris@16: Chris@16: /** Chris@16: * value type getter. Chris@16: * Chris@16: * Return: A constant reference to the protected value. Chris@16: * Chris@16: * Note: Not thread safe Chris@16: * Chris@16: */ Chris@16: T const& value() const Chris@16: { Chris@16: return value_; Chris@16: } Chris@16: /** Chris@16: * mutex getter. Chris@16: * Chris@16: * Return: A constant reference to the protecting mutex. Chris@16: * Chris@16: * Note: Not thread safe Chris@16: * Chris@16: */ Chris@16: mutex_type const& mutex() const Chris@16: { Chris@16: return mtx_; Chris@16: } Chris@16: /** Chris@16: * Swap Chris@16: * Chris@16: * Effects: Swaps the data. Again, locks are acquired using lock(). The mutexes are not swapped. Chris@16: * A swap method accepts a T& and swaps the data inside a critical section. Chris@16: * This is by far the preferred method of changing the guarded datum wholesale because it keeps the lock only Chris@16: * for a short time, thus lowering the pressure on the mutex. Chris@16: */ Chris@16: void swap(synchronized_value & rhs) Chris@16: { Chris@16: if (this == &rhs) { Chris@16: return; Chris@16: } Chris@16: // auto _ = make_unique_locks(mtx_, rhs.mtx_); Chris@16: unique_lock lk1(mtx_, defer_lock); Chris@16: unique_lock lk2(rhs.mtx_, defer_lock); Chris@16: lock(lk1,lk2); Chris@16: boost::swap(value_, rhs.value_); Chris@16: } Chris@16: /** Chris@16: * Swap with the underlying value type Chris@16: * Chris@16: * Effects: Swaps the data on a scope protected by the mutex. Chris@16: */ Chris@16: void swap(value_type & rhs) Chris@16: { Chris@16: strict_lock lk(mtx_); Chris@16: boost::swap(value_, rhs); Chris@16: } Chris@16: Chris@16: /** Chris@16: * Essentially calling a method obj->foo(x, y, z) calls the method foo(x, y, z) inside a critical section as Chris@16: * long-lived as the call itself. Chris@16: */ Chris@16: strict_lock_ptr operator->() Chris@16: { Chris@16: return BOOST_THREAD_MAKE_RV_REF((strict_lock_ptr(value_, mtx_))); Chris@16: } Chris@16: /** Chris@16: * If the synchronized_value object involved is const-qualified, then you'll only be able to call const methods Chris@16: * through operator->. So, for example, vec->push_back("xyz") won't work if vec were const-qualified. Chris@16: * The locking mechanism capitalizes on the assumption that const methods don't modify their underlying data. Chris@16: */ Chris@16: const_strict_lock_ptr operator->() const Chris@16: { Chris@16: return BOOST_THREAD_MAKE_RV_REF((const_strict_lock_ptr(value_, mtx_))); Chris@16: } Chris@16: Chris@16: /** Chris@16: * Call function on a locked block. Chris@16: * Chris@16: * @requires fct(value_) is well formed. Chris@16: * Chris@16: * Example Chris@16: * void fun(synchronized_value> & v) { Chris@16: * v ( [](vector> & vec) Chris@16: * { Chris@16: * vec.push_back(42); Chris@16: * assert(vec.back() == 42); Chris@16: * } ); Chris@16: * } Chris@16: */ Chris@16: template Chris@16: inline Chris@16: typename boost::result_of::type Chris@16: operator()(BOOST_THREAD_RV_REF(F) fct) Chris@16: { Chris@16: strict_lock lk(mtx_); Chris@16: return fct(value_); Chris@16: } Chris@16: template Chris@16: inline Chris@16: typename boost::result_of::type Chris@16: operator()(BOOST_THREAD_RV_REF(F) fct) const Chris@16: { Chris@16: strict_lock lk(mtx_); Chris@16: return fct(value_); Chris@16: } Chris@16: Chris@16: Chris@16: #if defined BOOST_NO_CXX11_RVALUE_REFERENCES Chris@16: template Chris@16: inline Chris@16: typename boost::result_of::type Chris@16: operator()(F const & fct) Chris@16: { Chris@16: strict_lock lk(mtx_); Chris@16: return fct(value_); Chris@16: } Chris@16: template Chris@16: inline Chris@16: typename boost::result_of::type Chris@16: operator()(F const & fct) const Chris@16: { Chris@16: strict_lock lk(mtx_); Chris@16: return fct(value_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline Chris@16: R operator()(R(*fct)(value_type&)) Chris@16: { Chris@16: strict_lock lk(mtx_); Chris@16: return fct(value_); Chris@16: } Chris@16: template Chris@16: inline Chris@16: R operator()(R(*fct)(value_type const&)) const Chris@16: { Chris@16: strict_lock lk(mtx_); Chris@16: return fct(value_); Chris@16: } Chris@16: #endif Chris@16: Chris@16: Chris@16: /** Chris@16: * The synchronize() factory make easier to lock on a scope. Chris@16: * As discussed, operator-> can only lock over the duration of a call, so it is insufficient for complex operations. Chris@16: * With synchronize() you get to lock the object in a scoped and to directly access the object inside that scope. Chris@16: * Chris@16: * Example Chris@16: * void fun(synchronized_value> & v) { Chris@16: * auto&& vec=v.synchronize(); Chris@16: * vec.push_back(42); Chris@16: * assert(vec.back() == 42); Chris@16: * } Chris@16: */ Chris@16: strict_lock_ptr synchronize() Chris@16: { Chris@16: return BOOST_THREAD_MAKE_RV_REF((strict_lock_ptr(value_, mtx_))); Chris@16: } Chris@16: const_strict_lock_ptr synchronize() const Chris@16: { Chris@16: return BOOST_THREAD_MAKE_RV_REF((const_strict_lock_ptr(value_, mtx_))); Chris@16: } Chris@16: Chris@16: unique_lock_ptr unique_synchronize() Chris@16: { Chris@16: return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr(value_, mtx_))); Chris@16: } Chris@16: const_unique_lock_ptr unique_synchronize() const Chris@16: { Chris@16: return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr(value_, mtx_))); Chris@16: } Chris@16: unique_lock_ptr unique_synchronize(defer_lock_t tag) Chris@16: { Chris@16: return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr(value_, mtx_, tag))); Chris@16: } Chris@16: const_unique_lock_ptr unique_synchronize(defer_lock_t tag) const Chris@16: { Chris@16: return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr(value_, mtx_, tag))); Chris@16: } Chris@16: unique_lock_ptr defer_synchronize() BOOST_NOEXCEPT Chris@16: { Chris@16: return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr(value_, mtx_, defer_lock))); Chris@16: } Chris@16: const_unique_lock_ptr defer_synchronize() const BOOST_NOEXCEPT Chris@16: { Chris@16: return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr(value_, mtx_, defer_lock))); Chris@16: } Chris@16: unique_lock_ptr try_to_synchronize() BOOST_NOEXCEPT Chris@16: { Chris@16: return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr(value_, mtx_, try_to_lock))); Chris@16: } Chris@16: const_unique_lock_ptr try_to_synchronize() const BOOST_NOEXCEPT Chris@16: { Chris@16: return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr(value_, mtx_, try_to_lock))); Chris@16: } Chris@16: unique_lock_ptr adopt_synchronize() BOOST_NOEXCEPT Chris@16: { Chris@16: return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr(value_, mtx_, adopt_lock))); Chris@16: } Chris@16: const_unique_lock_ptr adopt_synchronize() const BOOST_NOEXCEPT Chris@16: { Chris@16: return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr(value_, mtx_, adopt_lock))); Chris@16: } Chris@16: Chris@16: Chris@16: #if ! defined __IBMCPP__ Chris@16: private: Chris@16: #endif Chris@16: class deref_value Chris@16: { Chris@16: private: Chris@16: friend class synchronized_value; Chris@16: Chris@16: boost::unique_lock lk_; Chris@16: T& value_; Chris@16: Chris@16: explicit deref_value(synchronized_value& outer): Chris@16: lk_(outer.mtx_),value_(outer.value_) Chris@16: {} Chris@16: Chris@16: public: Chris@16: BOOST_THREAD_MOVABLE_ONLY(deref_value) Chris@16: Chris@16: deref_value(BOOST_THREAD_RV_REF(deref_value) other): Chris@16: lk_(boost::move(BOOST_THREAD_RV(other).lk_)),value_(BOOST_THREAD_RV(other).value_) Chris@16: {} Chris@16: operator T&() Chris@16: { Chris@16: return value_; Chris@16: } Chris@16: Chris@16: deref_value& operator=(T const& newVal) Chris@16: { Chris@16: value_=newVal; Chris@16: return *this; Chris@16: } Chris@16: }; Chris@16: class const_deref_value Chris@16: { Chris@16: private: Chris@16: friend class synchronized_value; Chris@16: Chris@16: boost::unique_lock lk_; Chris@16: const T& value_; Chris@16: Chris@16: explicit const_deref_value(synchronized_value const& outer): Chris@16: lk_(outer.mtx_), value_(outer.value_) Chris@16: {} Chris@16: Chris@16: public: Chris@16: BOOST_THREAD_MOVABLE_ONLY(const_deref_value) Chris@16: Chris@16: const_deref_value(BOOST_THREAD_RV_REF(const_deref_value) other): Chris@16: lk_(boost::move(BOOST_THREAD_RV(other).lk_)), value_(BOOST_THREAD_RV(other).value_) Chris@16: {} Chris@16: Chris@16: operator const T&() Chris@16: { Chris@16: return value_; Chris@16: } Chris@16: }; Chris@16: Chris@16: public: Chris@16: deref_value operator*() Chris@16: { Chris@16: return BOOST_THREAD_MAKE_RV_REF(deref_value(*this)); Chris@16: } Chris@16: Chris@16: const_deref_value operator*() const Chris@16: { Chris@16: return BOOST_THREAD_MAKE_RV_REF(const_deref_value(*this)); Chris@16: } Chris@16: Chris@16: // io functions Chris@16: /** Chris@16: * @requires T is OutputStreamable Chris@16: * @effects saves the value type on the output stream @c os. Chris@16: */ Chris@16: template Chris@16: void save(OStream& os) const Chris@16: { Chris@16: strict_lock lk(mtx_); Chris@16: os << value_; Chris@16: } Chris@16: /** Chris@16: * @requires T is InputStreamable Chris@16: * @effects loads the value type from the input stream @c is. Chris@16: */ Chris@16: template Chris@16: void load(IStream& is) const Chris@16: { Chris@16: strict_lock lk(mtx_); Chris@16: is >> value_; Chris@16: } Chris@16: Chris@16: // relational operators Chris@16: /** Chris@16: * @requires T is EqualityComparable Chris@16: * Chris@16: */ Chris@16: bool operator==(synchronized_value const& rhs) const Chris@16: { Chris@16: unique_lock lk1(mtx_, defer_lock); Chris@16: unique_lock lk2(rhs.mtx_, defer_lock); Chris@16: lock(lk1,lk2); Chris@16: Chris@16: return value_ == rhs.value_; Chris@16: } Chris@16: /** Chris@16: * @requires T is LessThanComparable Chris@16: * Chris@16: */ Chris@16: bool operator<(synchronized_value const& rhs) const Chris@16: { Chris@16: unique_lock lk1(mtx_, defer_lock); Chris@16: unique_lock lk2(rhs.mtx_, defer_lock); Chris@16: lock(lk1,lk2); Chris@16: Chris@16: return value_ < rhs.value_; Chris@16: } Chris@16: /** Chris@16: * @requires T is GreaterThanComparable Chris@16: * Chris@16: */ Chris@16: bool operator>(synchronized_value const& rhs) const Chris@16: { Chris@16: unique_lock lk1(mtx_, defer_lock); Chris@16: unique_lock lk2(rhs.mtx_, defer_lock); Chris@16: lock(lk1,lk2); Chris@16: Chris@16: return value_ > rhs.value_; Chris@16: } Chris@16: bool operator<=(synchronized_value const& rhs) const Chris@16: { Chris@16: unique_lock lk1(mtx_, defer_lock); Chris@16: unique_lock lk2(rhs.mtx_, defer_lock); Chris@16: lock(lk1,lk2); Chris@16: Chris@16: return value_ <= rhs.value_; Chris@16: } Chris@16: bool operator>=(synchronized_value const& rhs) const Chris@16: { Chris@16: unique_lock lk1(mtx_, defer_lock); Chris@16: unique_lock lk2(rhs.mtx_, defer_lock); Chris@16: lock(lk1,lk2); Chris@16: Chris@16: return value_ >= rhs.value_; Chris@16: } Chris@16: bool operator==(value_type const& rhs) const Chris@16: { Chris@16: unique_lock lk1(mtx_); Chris@16: Chris@16: return value_ == rhs; Chris@16: } Chris@16: bool operator!=(value_type const& rhs) const Chris@16: { Chris@16: unique_lock lk1(mtx_); Chris@16: Chris@16: return value_ != rhs; Chris@16: } Chris@16: bool operator<(value_type const& rhs) const Chris@16: { Chris@16: unique_lock lk1(mtx_); Chris@16: Chris@16: return value_ < rhs; Chris@16: } Chris@16: bool operator<=(value_type const& rhs) const Chris@16: { Chris@16: unique_lock lk1(mtx_); Chris@16: Chris@16: return value_ <= rhs; Chris@16: } Chris@16: bool operator>(value_type const& rhs) const Chris@16: { Chris@16: unique_lock lk1(mtx_); Chris@16: Chris@16: return value_ > rhs; Chris@16: } Chris@16: bool operator>=(value_type const& rhs) const Chris@16: { Chris@16: unique_lock lk1(mtx_); Chris@16: Chris@16: return value_ >= rhs; Chris@16: } Chris@16: Chris@16: }; Chris@16: Chris@16: // Specialized algorithms Chris@16: /** Chris@16: * Chris@16: */ Chris@16: template Chris@16: inline void swap(synchronized_value & lhs, synchronized_value & rhs) Chris@16: { Chris@16: lhs.swap(rhs); Chris@16: } Chris@16: template Chris@16: inline void swap(synchronized_value & lhs, T & rhs) Chris@16: { Chris@16: lhs.swap(rhs); Chris@16: } Chris@16: template Chris@16: inline void swap(T & lhs, synchronized_value & rhs) Chris@16: { Chris@16: rhs.swap(lhs); Chris@16: } Chris@16: Chris@16: //Hash support Chris@16: Chris@16: // template struct hash; Chris@16: // template Chris@16: // struct hash >; Chris@16: Chris@16: // Comparison with T Chris@16: template Chris@16: bool operator!=(synchronized_value const&lhs, synchronized_value const& rhs) Chris@16: { Chris@16: return ! (lhs==rhs); Chris@16: } Chris@16: Chris@16: template Chris@16: bool operator==(T const& lhs, synchronized_value const&rhs) Chris@16: { Chris@16: return rhs==lhs; Chris@16: } Chris@16: template Chris@16: bool operator!=(T const& lhs, synchronized_value const&rhs) Chris@16: { Chris@16: return rhs!=lhs; Chris@16: } Chris@16: template Chris@16: bool operator<(T const& lhs, synchronized_value const&rhs) Chris@16: { Chris@16: return rhs>=lhs; Chris@16: } Chris@16: template Chris@16: bool operator<=(T const& lhs, synchronized_value const&rhs) Chris@16: { Chris@16: return rhs>lhs; Chris@16: } Chris@16: template Chris@16: bool operator>(T const& lhs, synchronized_value const&rhs) Chris@16: { Chris@16: return rhs<=lhs; Chris@16: } Chris@16: template Chris@16: bool operator>=(T const& lhs, synchronized_value const&rhs) Chris@16: { Chris@16: return rhs Chris@16: inline OStream& operator<<(OStream& os, synchronized_value const& rhs) Chris@16: { Chris@16: rhs.save(os); Chris@16: return os; Chris@16: } Chris@16: template Chris@16: inline IStream& operator>>(IStream& is, synchronized_value const& rhs) Chris@16: { Chris@16: rhs.load(is); Chris@16: return is; Chris@16: } Chris@16: Chris@16: #if ! defined(BOOST_THREAD_NO_SYNCHRONIZE) Chris@16: #if ! defined BOOST_NO_CXX11_VARIADIC_TEMPLATES Chris@16: Chris@16: template Chris@16: std::tuple::type ...> synchronize(SV& ...sv) Chris@16: { Chris@16: boost::lock(sv.mtx_ ...); Chris@16: typedef std::tuple::type ...> t_type; Chris@16: Chris@16: return t_type(typename synchronized_value_strict_lock_ptr::type(sv.value_, sv.mtx_, adopt_lock) ...); Chris@16: } Chris@16: #else Chris@16: Chris@16: template Chris@16: std::tuple< Chris@16: typename synchronized_value_strict_lock_ptr::type, Chris@16: typename synchronized_value_strict_lock_ptr::type Chris@16: > Chris@16: synchronize(SV1& sv1, SV2& sv2) Chris@16: { Chris@16: boost::lock(sv1.mtx_, sv2.mtx_); Chris@16: typedef std::tuple< Chris@16: typename synchronized_value_strict_lock_ptr::type, Chris@16: typename synchronized_value_strict_lock_ptr::type Chris@16: > t_type; Chris@16: Chris@16: return t_type( Chris@16: typename synchronized_value_strict_lock_ptr::type(sv1.value_, sv1.mtx_, adopt_lock), Chris@16: typename synchronized_value_strict_lock_ptr::type(sv2.value_, sv2.mtx_, adopt_lock) Chris@16: ); Chris@16: Chris@16: } Chris@16: template Chris@16: std::tuple< Chris@16: typename synchronized_value_strict_lock_ptr::type, Chris@16: typename synchronized_value_strict_lock_ptr::type, Chris@16: typename synchronized_value_strict_lock_ptr::type Chris@16: > Chris@16: synchronize(SV1& sv1, SV2& sv2, SV3& sv3) Chris@16: { Chris@16: boost::lock(sv1.mtx_, sv2.mtx_); Chris@16: typedef std::tuple< Chris@16: typename synchronized_value_strict_lock_ptr::type, Chris@16: typename synchronized_value_strict_lock_ptr::type, Chris@16: typename synchronized_value_strict_lock_ptr::type Chris@16: > t_type; Chris@16: Chris@16: return t_type( Chris@16: typename synchronized_value_strict_lock_ptr::type(sv1.value_, sv1.mtx_, adopt_lock), Chris@16: typename synchronized_value_strict_lock_ptr::type(sv2.value_, sv2.mtx_, adopt_lock), Chris@16: typename synchronized_value_strict_lock_ptr::type(sv3.value_, sv3.mtx_, adopt_lock) Chris@16: ); Chris@16: Chris@16: } Chris@16: #endif Chris@16: #endif Chris@16: } Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // header