1[/ 2 / Copyright (c) 2013 Vicente J. Botet Escriba 3 / 4 / Distributed under the Boost Software License, Version 1.0. (See accompanying 5 / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 /] 7 8[section:synchronized_value_ref Reference ] 9 10 11 #include <boost/thread/synchronized_value.hpp> 12 namespace boost 13 { 14 15 template<typename T, typename Lockable = mutex> 16 class synchronized_value; 17 18 // Specialized swap algorithm 19 template <typename T, typename L> 20 void swap(synchronized_value<T,L> & lhs, synchronized_value<T,L> & rhs); 21 template <typename T, typename L> 22 void swap(synchronized_value<T,L> & lhs, T & rhs); 23 template <typename T, typename L> 24 void swap(T & lhs, synchronized_value<T,L> & rhs); 25 26 // Hash support 27 template<typename T, typename L> 28 struct hash<synchronized_value<T,L> >; 29 30 // Comparison 31 template <typename T, typename L> 32 bool operator==(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs) 33 template <typename T, typename L> 34 bool operator!=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs) 35 template <typename T, typename L> 36 bool operator<(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs) 37 template <typename T, typename L> 38 bool operator<=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs) 39 template <typename T, typename L> 40 bool operator>(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs) 41 template <typename T, typename L> 42 bool operator>=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs) 43 44 // Comparison with T 45 template <typename T, typename L> 46 bool operator==(T const& lhs, synchronized_value<T,L> const&rhs); 47 template <typename T, typename L> 48 bool operator!=(T const& lhs, synchronized_value<T,L> const&rhs); 49 template <typename T, typename L> 50 bool operator<(T const& lhs, synchronized_value<T,L> const&rhs); 51 template <typename T, typename L> 52 bool operator<=(T const& lhs, synchronized_value<T,L> const&rhs); 53 template <typename T, typename L> 54 bool operator>(T const& lhs, synchronized_value<T,L> const&rhs); 55 template <typename T, typename L> 56 bool operator>=(T const& lhs, synchronized_value<T,L> const&rhs); 57 58 template <typename T, typename L> 59 bool operator==(synchronized_value<T,L> const& lhs, T const& rhs); 60 template <typename T, typename L> 61 bool operator!=(synchronized_value<T,L> const& lhs, T const& rhs); 62 template <typename T, typename L> 63 bool operator<(synchronized_value<T,L> const& lhs, T const& rhs); 64 template <typename T, typename L> 65 bool operator<=(synchronized_value<T,L> const& lhs, T const& rhs); 66 template <typename T, typename L> 67 bool operator>(synchronized_value<T,L> const& lhs, T const& rhs); 68 template <typename T, typename L> 69 bool operator>=(synchronized_value<T,L> const& lhs, T const& rhs); 70 71 #if ! defined(BOOST_THREAD_NO_SYNCHRONIZE) 72 template <typename ...SV> 73 std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> synchronize(SV& ...sv); 74 #endif 75 } 76 77[section:synchronized_value Class `synchronized_value`] 78 79 #include <boost/thread/synchronized_value.hpp> 80 81 namespace boost 82 { 83 84 template<typename T, typename Lockable = mutex> 85 class synchronized_value 86 { 87 public: 88 typedef T value_type; 89 typedef Lockable mutex_type; 90 91 synchronized_value() noexcept(is_nothrow_default_constructible<T>::value); 92 synchronized_value(T const& other) noexcept(is_nothrow_copy_constructible<T>::value); 93 synchronized_value(T&& other) noexcept(is_nothrow_move_constructible<T>::value); 94 synchronized_value(synchronized_value const& rhs); 95 synchronized_value(synchronized_value&& other); 96 97 // mutation 98 synchronized_value& operator=(synchronized_value const& rhs); 99 synchronized_value& operator=(value_type const& val); 100 void swap(synchronized_value & rhs); 101 void swap(value_type & rhs); 102 103 //observers 104 T get() const; 105 #if ! defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) 106 explicit operator T() const; 107 #endif 108 109 strict_lock_ptr<T,Lockable> operator->(); 110 const_strict_lock_ptr<T,Lockable> operator->() const; 111 strict_lock_ptr<T,Lockable> synchronize(); 112 const_strict_lock_ptr<T,Lockable> synchronize() const; 113 114 deref_value operator*();; 115 const_deref_value operator*() const; 116 117 private: 118 T value_; // for exposition only 119 mutable mutex_type mtx_; // for exposition only 120 }; 121 } 122 123[variablelist 124 125[[Requires:] [`Lockable` is `Lockable`.]] 126 127] 128 129 130[section:constructor `synchronized_value()`] 131 132 synchronized_value() noexcept(is_nothrow_default_constructible<T>::value); 133 134[variablelist 135 136[[Requires:] [`T` is `DefaultConstructible`.]] 137[[Effects:] [Default constructs the cloaked value_type]] 138 139[[Throws:] [Any exception thrown by `value_type()`.]] 140 141] 142 143[endsect] 144 145 146[section:constructor_vt `synchronized_value(T const&)`] 147 148 synchronized_value(T const& other) noexcept(is_nothrow_copy_constructible<T>::value); 149 150[variablelist 151 152[[Requires:] [`T` is `CopyConstructible`.]] 153[[Effects:] [Copy constructs the cloaked value_type using the parameter `other`]] 154 155[[Throws:] [Any exception thrown by `value_type(other)`.]] 156 157] 158 159[endsect] 160 161[section:copy_cons `synchronized_value(synchronized_value const&)`] 162 163 synchronized_value(synchronized_value const& rhs); 164 165[variablelist 166 167[[Requires:] [`T` is `DefaultConstructible` and `Assignable`.]] 168[[Effects:] [Assigns the value on a scope protected by the mutex of the rhs. The mutex is not copied.]] 169 170[[Throws:] [Any exception thrown by `value_type()` or `value_type& operator=(value_type&)` or `mtx_.lock()`.]] 171 172] 173 174[endsect] 175 176[section:move_vt `synchronized_value(T&&)`] 177 178 synchronized_value(T&& other) noexcept(is_nothrow_move_constructible<T>::value); 179 180[variablelist 181 182[[Requires:] [`T` is `MoveConstructible `.]] 183[[Effects:] [Move constructs the cloaked value_type]] 184 185[[Throws:] [Any exception thrown by `value_type(value_type&&)`.]] 186 187] 188 189[endsect] 190 191[section:move `synchronized_value(synchronized_value&&)`] 192 193 synchronized_value(synchronized_value&& other); 194 195[variablelist 196 197[[Requires:] [`T` is `MoveConstructible `.]] 198[[Effects:] [Move constructs the cloaked value_type]] 199 200[[Throws:] [Any exception thrown by `value_type(value_type&&)` or `mtx_.lock()`.]] 201 202] 203 204[endsect] 205 206[section:assign `operator=(synchronized_value const&)`] 207 208 synchronized_value& operator=(synchronized_value const& rhs); 209 210[variablelist 211 212[[Requires:] [`T` is `Assignable`.]] 213[[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`.]] 214[[Return:] [`*this`]] 215 216[[Throws:] [Any exception thrown by `value_type& operator(value_type const&)` or `mtx_.lock()`.]] 217 218] 219 220[endsect] 221[section:assign_vt `operator=(T const&)`] 222 223 synchronized_value& operator=(value_type const& val); 224 225[variablelist 226 227[[Requires:] [`T` is `Assignable`.]] 228[[Effects:] [Copies the value on a scope protected by the mutex.]] 229[[Return:] [`*this`]] 230 231[[Throws:] [Any exception thrown by `value_type& operator(value_type const&)` or `mtx_.lock()`.]] 232 233] 234 235[endsect] 236 237[section:get `get() const`] 238 239 T get() const; 240 241[variablelist 242 243[[Requires:] [`T` is `CopyConstructible`.]] 244[[Return:] [`A copy of the protected value obtained on a scope protected by the mutex.`]] 245 246[[Throws:] [Any exception thrown by `value_type(value_type const&)` or `mtx_.lock()`.]] 247 248] 249 250[endsect] 251 252 253[section:T `operator T() const`] 254 255 #if ! defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) 256 explicit operator T() const; 257 #endif 258 259[variablelist 260 261[[Requires:] [`T` is `CopyConstructible`.]] 262[[Return:] [`A copy of the protected value obtained on a scope protected by the mutex.`]] 263 264[[Throws:] [Any exception thrown by `value_type(value_type const&)` or `mtx_.lock()`.]] 265 266] 267 268[endsect] 269 270[section:swap `swap(synchronized_value&)`] 271 272 void swap(synchronized_value & rhs); 273 274[variablelist 275 276[[Requires:] [`T` is `Assignable`.]] 277[[Effects:] [Swaps the data on a scope protected by both mutex. Both mutex are acquired to avoid dead-lock. The mutexes are not swapped.]] 278 279[[Throws:] [Any exception thrown by `swap(value_, rhs.value)` or `mtx_.lock()` or `rhs_.mtx_.lock()`.]] 280 281] 282 283[endsect] 284 285[section:swap_vt `swap(synchronized_value&)`] 286 287 void swap(value_type & rhs); 288 289[variablelist 290 291[[Requires:] [`T` is `Swapable`.]] 292[[Effects:] [Swaps the data on a scope protected by both mutex. Both mutex are acquired to avoid dead-lock. The mutexes are not swapped.]] 293 294[[Throws:] [Any exception thrown by `swap(value_, rhs)` or `mtx_.lock()`.]] 295 296] 297 298[endsect] 299[section:indir `operator->()`] 300 301 strict_lock_ptr<T,Lockable> operator->(); 302 303 304Essentially 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. 305 306[variablelist 307 308[[Return:] [`A strict_lock_ptr<>.`]] 309 310[[Throws:] [Nothing.]] 311 312] 313 314[endsect] 315[section:indir_const `operator->() const`] 316 317 const_strict_lock_ptr<T,Lockable> operator->() const; 318 319 320If the `synchronized_value` object involved is const-qualified, then you'll only be able to call const methods 321through `operator->`. So, for example, `vec->push_back("xyz")` won't work if `vec` were const-qualified. 322The locking mechanism capitalizes on the assumption that const methods don't modify their underlying data. 323 324[variablelist 325 326[[Return:] [`A const_strict_lock_ptr <>.`]] 327 328[[Throws:] [Nothing.]] 329 330] 331 332[endsect] 333[section:synchronize `synchronize()`] 334 335 strict_lock_ptr<T,Lockable> synchronize(); 336 337The 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. 338 339[*Example:] 340 341 void fun(synchronized_value<vector<int>> & vec) { 342 auto vec2=vec.synchronize(); 343 vec2.push_back(42); 344 assert(vec2.back() == 42); 345 } 346 347[variablelist 348 349[[Return:] [`A strict_lock_ptr <>.`]] 350 351[[Throws:] [Nothing.]] 352 353] 354 355[endsect] 356[section:synchronize_const `synchronize() const`] 357 358 const_strict_lock_ptr<T,Lockable> synchronize() const; 359 360[variablelist 361 362[[Return:] [`A const_strict_lock_ptr <>.`]] 363 364[[Throws:] [Nothing.]] 365 366] 367 368[endsect] 369 370[section:deref `operator*()`] 371 372 deref_value operator*();; 373 374[variablelist 375 376[[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.`]] 377 378[[Throws:] [Nothing.]] 379 380] 381 382[endsect] 383[section:deref_const `operator*() const`] 384 385 const_deref_value operator*() const; 386 387 388[variablelist 389 390[[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.`]] 391 392[[Throws:] [Nothing.]] 393 394] 395 396[endsect] 397 398 399 400 401[endsect] 402[section:synchronize Non-Member Function `synchronize`] 403 404 #include <boost/thread/synchronized_value.hpp> 405 namespace boost 406 { 407 #if ! defined(BOOST_THREAD_NO_SYNCHRONIZE) 408 template <typename ...SV> 409 std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> synchronize(SV& ...sv); 410 #endif 411 } 412 413[endsect] 414[endsect] 415 416