| [/ |
| / 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) |
| /] |
| |
| [section:synchronized_value_ref Reference ] |
| |
| |
| #include <boost/thread/synchronized_value.hpp> |
| namespace boost |
| { |
| |
| template<typename T, typename Lockable = mutex> |
| class synchronized_value; |
| |
| // Specialized swap algorithm |
| template <typename T, typename L> |
| void swap(synchronized_value<T,L> & lhs, synchronized_value<T,L> & rhs); |
| template <typename T, typename L> |
| void swap(synchronized_value<T,L> & lhs, T & rhs); |
| template <typename T, typename L> |
| void swap(T & lhs, synchronized_value<T,L> & rhs); |
| |
| // Hash support |
| template<typename T, typename L> |
| struct hash<synchronized_value<T,L> >; |
| |
| // Comparison |
| template <typename T, typename L> |
| bool operator==(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs) |
| template <typename T, typename L> |
| bool operator!=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs) |
| template <typename T, typename L> |
| bool operator<(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs) |
| template <typename T, typename L> |
| bool operator<=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs) |
| template <typename T, typename L> |
| bool operator>(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs) |
| template <typename T, typename L> |
| bool operator>=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs) |
| |
| // Comparison with T |
| template <typename T, typename L> |
| bool operator==(T const& lhs, synchronized_value<T,L> const&rhs); |
| template <typename T, typename L> |
| bool operator!=(T const& lhs, synchronized_value<T,L> const&rhs); |
| template <typename T, typename L> |
| bool operator<(T const& lhs, synchronized_value<T,L> const&rhs); |
| template <typename T, typename L> |
| bool operator<=(T const& lhs, synchronized_value<T,L> const&rhs); |
| template <typename T, typename L> |
| bool operator>(T const& lhs, synchronized_value<T,L> const&rhs); |
| template <typename T, typename L> |
| bool operator>=(T const& lhs, synchronized_value<T,L> const&rhs); |
| |
| template <typename T, typename L> |
| bool operator==(synchronized_value<T,L> const& lhs, T const& rhs); |
| template <typename T, typename L> |
| bool operator!=(synchronized_value<T,L> const& lhs, T const& rhs); |
| template <typename T, typename L> |
| bool operator<(synchronized_value<T,L> const& lhs, T const& rhs); |
| template <typename T, typename L> |
| bool operator<=(synchronized_value<T,L> const& lhs, T const& rhs); |
| template <typename T, typename L> |
| bool operator>(synchronized_value<T,L> const& lhs, T const& rhs); |
| template <typename T, typename L> |
| bool operator>=(synchronized_value<T,L> const& lhs, T const& rhs); |
| |
| #if ! defined(BOOST_THREAD_NO_SYNCHRONIZE) |
| template <typename ...SV> |
| std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> synchronize(SV& ...sv); |
| #endif |
| } |
| |
| [section:synchronized_value Class `synchronized_value`] |
| |
| #include <boost/thread/synchronized_value.hpp> |
| |
| namespace boost |
| { |
| |
| template<typename T, typename Lockable = mutex> |
| class synchronized_value |
| { |
| public: |
| typedef T value_type; |
| typedef Lockable mutex_type; |
| |
| synchronized_value() noexcept(is_nothrow_default_constructible<T>::value); |
| synchronized_value(T const& other) noexcept(is_nothrow_copy_constructible<T>::value); |
| synchronized_value(T&& other) noexcept(is_nothrow_move_constructible<T>::value); |
| synchronized_value(synchronized_value const& rhs); |
| synchronized_value(synchronized_value&& other); |
| |
| // mutation |
| synchronized_value& operator=(synchronized_value const& rhs); |
| synchronized_value& operator=(value_type const& val); |
| void swap(synchronized_value & rhs); |
| void swap(value_type & rhs); |
| |
| //observers |
| T get() const; |
| #if ! defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) |
| explicit operator T() const; |
| #endif |
| |
| strict_lock_ptr<T,Lockable> operator->(); |
| const_strict_lock_ptr<T,Lockable> operator->() const; |
| strict_lock_ptr<T,Lockable> synchronize(); |
| const_strict_lock_ptr<T,Lockable> synchronize() const; |
| |
| deref_value operator*();; |
| const_deref_value operator*() const; |
| |
| private: |
| T value_; // for exposition only |
| mutable mutex_type mtx_; // for exposition only |
| }; |
| } |
| |
| [variablelist |
| |
| [[Requires:] [`Lockable` is `Lockable`.]] |
| |
| ] |
| |
| |
| [section:constructor `synchronized_value()`] |
| |
| synchronized_value() noexcept(is_nothrow_default_constructible<T>::value); |
| |
| [variablelist |
| |
| [[Requires:] [`T` is `DefaultConstructible`.]] |
| [[Effects:] [Default constructs the cloaked value_type]] |
| |
| [[Throws:] [Any exception thrown by `value_type()`.]] |
| |
| ] |
| |
| [endsect] |
| |
| |
| [section:constructor_vt `synchronized_value(T const&)`] |
| |
| synchronized_value(T const& other) noexcept(is_nothrow_copy_constructible<T>::value); |
| |
| [variablelist |
| |
| [[Requires:] [`T` is `CopyConstructible`.]] |
| [[Effects:] [Copy constructs the cloaked value_type using the parameter `other`]] |
| |
| [[Throws:] [Any exception thrown by `value_type(other)`.]] |
| |
| ] |
| |
| [endsect] |
| |
| [section:copy_cons `synchronized_value(synchronized_value const&)`] |
| |
| synchronized_value(synchronized_value const& rhs); |
| |
| [variablelist |
| |
| [[Requires:] [`T` is `DefaultConstructible` and `Assignable`.]] |
| [[Effects:] [Assigns the value on a scope protected by the mutex of the rhs. The mutex is not copied.]] |
| |
| [[Throws:] [Any exception thrown by `value_type()` or `value_type& operator=(value_type&)` or `mtx_.lock()`.]] |
| |
| ] |
| |
| [endsect] |
| |
| [section:move_vt `synchronized_value(T&&)`] |
| |
| synchronized_value(T&& other) noexcept(is_nothrow_move_constructible<T>::value); |
| |
| [variablelist |
| |
| [[Requires:] [`T` is `MoveConstructible `.]] |
| [[Effects:] [Move constructs the cloaked value_type]] |
| |
| [[Throws:] [Any exception thrown by `value_type(value_type&&)`.]] |
| |
| ] |
| |
| [endsect] |
| |
| [section:move `synchronized_value(synchronized_value&&)`] |
| |
| synchronized_value(synchronized_value&& other); |
| |
| [variablelist |
| |
| [[Requires:] [`T` is `MoveConstructible `.]] |
| [[Effects:] [Move constructs the cloaked value_type]] |
| |
| [[Throws:] [Any exception thrown by `value_type(value_type&&)` or `mtx_.lock()`.]] |
| |
| ] |
| |
| [endsect] |
| |
| [section:assign `operator=(synchronized_value const&)`] |
| |
| synchronized_value& operator=(synchronized_value const& rhs); |
| |
| [variablelist |
| |
| [[Requires:] [`T` is `Assignable`.]] |
| [[Effects:] [Copies the underlying value on a scope protected by the two mutexes. The mutex is not copied. The locks are acquired avoiding deadlock. For example, there is no problem if one thread assigns `a = b` and the other assigns `b = a`.]] |
| [[Return:] [`*this`]] |
| |
| [[Throws:] [Any exception thrown by `value_type& operator(value_type const&)` or `mtx_.lock()`.]] |
| |
| ] |
| |
| [endsect] |
| [section:assign_vt `operator=(T const&)`] |
| |
| synchronized_value& operator=(value_type const& val); |
| |
| [variablelist |
| |
| [[Requires:] [`T` is `Assignable`.]] |
| [[Effects:] [Copies the value on a scope protected by the mutex.]] |
| [[Return:] [`*this`]] |
| |
| [[Throws:] [Any exception thrown by `value_type& operator(value_type const&)` or `mtx_.lock()`.]] |
| |
| ] |
| |
| [endsect] |
| |
| [section:get `get() const`] |
| |
| T get() const; |
| |
| [variablelist |
| |
| [[Requires:] [`T` is `CopyConstructible`.]] |
| [[Return:] [`A copy of the protected value obtained on a scope protected by the mutex.`]] |
| |
| [[Throws:] [Any exception thrown by `value_type(value_type const&)` or `mtx_.lock()`.]] |
| |
| ] |
| |
| [endsect] |
| |
| |
| [section:T `operator T() const`] |
| |
| #if ! defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) |
| explicit operator T() const; |
| #endif |
| |
| [variablelist |
| |
| [[Requires:] [`T` is `CopyConstructible`.]] |
| [[Return:] [`A copy of the protected value obtained on a scope protected by the mutex.`]] |
| |
| [[Throws:] [Any exception thrown by `value_type(value_type const&)` or `mtx_.lock()`.]] |
| |
| ] |
| |
| [endsect] |
| |
| [section:swap `swap(synchronized_value&)`] |
| |
| void swap(synchronized_value & rhs); |
| |
| [variablelist |
| |
| [[Requires:] [`T` is `Assignable`.]] |
| [[Effects:] [Swaps the data on a scope protected by both mutex. Both mutex are acquired to avoid dead-lock. The mutexes are not swapped.]] |
| |
| [[Throws:] [Any exception thrown by `swap(value_, rhs.value)` or `mtx_.lock()` or `rhs_.mtx_.lock()`.]] |
| |
| ] |
| |
| [endsect] |
| |
| [section:swap_vt `swap(synchronized_value&)`] |
| |
| void swap(value_type & rhs); |
| |
| [variablelist |
| |
| [[Requires:] [`T` is `Swapable`.]] |
| [[Effects:] [Swaps the data on a scope protected by both mutex. Both mutex are acquired to avoid dead-lock. The mutexes are not swapped.]] |
| |
| [[Throws:] [Any exception thrown by `swap(value_, rhs)` or `mtx_.lock()`.]] |
| |
| ] |
| |
| [endsect] |
| [section:indir `operator->()`] |
| |
| strict_lock_ptr<T,Lockable> operator->(); |
| |
| |
| 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. |
| |
| [variablelist |
| |
| [[Return:] [`A strict_lock_ptr<>.`]] |
| |
| [[Throws:] [Nothing.]] |
| |
| ] |
| |
| [endsect] |
| [section:indir_const `operator->() const`] |
| |
| const_strict_lock_ptr<T,Lockable> operator->() const; |
| |
| |
| If the `synchronized_value` object involved is const-qualified, then you'll only be able to call const methods |
| through `operator->`. So, for example, `vec->push_back("xyz")` won't work if `vec` were const-qualified. |
| The locking mechanism capitalizes on the assumption that const methods don't modify their underlying data. |
| |
| [variablelist |
| |
| [[Return:] [`A const_strict_lock_ptr <>.`]] |
| |
| [[Throws:] [Nothing.]] |
| |
| ] |
| |
| [endsect] |
| [section:synchronize `synchronize()`] |
| |
| strict_lock_ptr<T,Lockable> synchronize(); |
| |
| 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<vector<int>> & vec) { |
| auto vec2=vec.synchronize(); |
| vec2.push_back(42); |
| assert(vec2.back() == 42); |
| } |
| |
| [variablelist |
| |
| [[Return:] [`A strict_lock_ptr <>.`]] |
| |
| [[Throws:] [Nothing.]] |
| |
| ] |
| |
| [endsect] |
| [section:synchronize_const `synchronize() const`] |
| |
| const_strict_lock_ptr<T,Lockable> synchronize() const; |
| |
| [variablelist |
| |
| [[Return:] [`A const_strict_lock_ptr <>.`]] |
| |
| [[Throws:] [Nothing.]] |
| |
| ] |
| |
| [endsect] |
| |
| [section:deref `operator*()`] |
| |
| deref_value operator*();; |
| |
| [variablelist |
| |
| [[Return:] [`A an instance of a class that locks the mutex on construction and unlocks it on destruction and provides implicit conversion to a reference to the protected value.`]] |
| |
| [[Throws:] [Nothing.]] |
| |
| ] |
| |
| [endsect] |
| [section:deref_const `operator*() const`] |
| |
| const_deref_value operator*() const; |
| |
| |
| [variablelist |
| |
| [[Return:] [`A an instance of a class that locks the mutex on construction and unlocks it on destruction and provides implicit conversion to a constant reference to the protected value.`]] |
| |
| [[Throws:] [Nothing.]] |
| |
| ] |
| |
| [endsect] |
| |
| |
| |
| |
| [endsect] |
| [section:synchronize Non-Member Function `synchronize`] |
| |
| #include <boost/thread/synchronized_value.hpp> |
| namespace boost |
| { |
| #if ! defined(BOOST_THREAD_NO_SYNCHRONIZE) |
| template <typename ...SV> |
| std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> synchronize(SV& ...sv); |
| #endif |
| } |
| |
| [endsect] |
| [endsect] |
| |