[/ / 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 namespace boost { template class synchronized_value; // Specialized swap algorithm template void swap(synchronized_value & lhs, synchronized_value & rhs); template void swap(synchronized_value & lhs, T & rhs); template void swap(T & lhs, synchronized_value & rhs); // Hash support template struct hash >; // Comparison template bool operator==(synchronized_value const&lhs, synchronized_value const& rhs) template bool operator!=(synchronized_value const&lhs, synchronized_value const& rhs) template bool operator<(synchronized_value const&lhs, synchronized_value const& rhs) template bool operator<=(synchronized_value const&lhs, synchronized_value const& rhs) template bool operator>(synchronized_value const&lhs, synchronized_value const& rhs) template bool operator>=(synchronized_value const&lhs, synchronized_value const& rhs) // Comparison with T template bool operator==(T const& lhs, synchronized_value const&rhs); template bool operator!=(T const& lhs, synchronized_value const&rhs); template bool operator<(T const& lhs, synchronized_value const&rhs); template bool operator<=(T const& lhs, synchronized_value const&rhs); template bool operator>(T const& lhs, synchronized_value const&rhs); template bool operator>=(T const& lhs, synchronized_value const&rhs); template bool operator==(synchronized_value const& lhs, T const& rhs); template bool operator!=(synchronized_value const& lhs, T const& rhs); template bool operator<(synchronized_value const& lhs, T const& rhs); template bool operator<=(synchronized_value const& lhs, T const& rhs); template bool operator>(synchronized_value const& lhs, T const& rhs); template bool operator>=(synchronized_value const& lhs, T const& rhs); #if ! defined(BOOST_THREAD_NO_SYNCHRONIZE) template std::tuple::type ...> synchronize(SV& ...sv); #endif } [section:synchronized_value Class `synchronized_value`] #include namespace boost { template class synchronized_value { public: typedef T value_type; typedef Lockable mutex_type; synchronized_value() noexcept(is_nothrow_default_constructible::value); synchronized_value(T const& other) noexcept(is_nothrow_copy_constructible::value); synchronized_value(T&& other) noexcept(is_nothrow_move_constructible::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 operator->(); const_strict_lock_ptr operator->() const; strict_lock_ptr synchronize(); const_strict_lock_ptr 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::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::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::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 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 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 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> & 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 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 namespace boost { #if ! defined(BOOST_THREAD_NO_SYNCHRONIZE) template std::tuple::type ...> synchronize(SV& ...sv); #endif } [endsect] [endsect]