1 // (C) Copyright 2010 Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
2 // (C) Copyright 2012 Vicente J. Botet Escriba
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 
7 
8 #ifndef BOOST_THREAD_SYNCHRONIZED_VALUE_HPP
9 #define BOOST_THREAD_SYNCHRONIZED_VALUE_HPP
10 
11 #include <boost/thread/detail/config.hpp>
12 
13 #include <boost/thread/detail/move.hpp>
14 #include <boost/thread/mutex.hpp>
15 #include <boost/thread/lock_types.hpp>
16 #include <boost/thread/lock_guard.hpp>
17 #include <boost/thread/lock_algorithms.hpp>
18 #include <boost/thread/lock_factories.hpp>
19 #include <boost/thread/strict_lock.hpp>
20 #include <boost/core/swap.hpp>
21 #include <boost/utility/declval.hpp>
22 //#include <boost/type_traits.hpp>
23 //#include <boost/thread/detail/is_nothrow_default_constructible.hpp>
24 //#if ! defined BOOST_NO_CXX11_HDR_TYPE_TRAITS
25 //#include <type_traits>
26 //#endif
27 
28 #if ! defined(BOOST_THREAD_NO_SYNCHRONIZE)
29 #include <tuple> // todo change to <boost/tuple.hpp> once Boost.Tuple or Boost.Fusion provides Move semantics on C++98 compilers.
30 #include <functional>
31 #endif
32 
33 #include <boost/utility/result_of.hpp>
34 
35 #include <boost/config/abi_prefix.hpp>
36 
37 namespace boost
38 {
39 
40   /**
41    * strict lock providing a const pointer access to the synchronized value type.
42    *
43    * @param T the value type.
44    * @param Lockable the mutex type protecting the value type.
45    */
46   template <typename T, typename Lockable = mutex>
47   class const_strict_lock_ptr
48   {
49   public:
50     typedef T value_type;
51     typedef Lockable mutex_type;
52   protected:
53 
54     // this should be a strict_lock, but unique_lock is needed to be able to return it.
55     boost::unique_lock<mutex_type> lk_;
56     T const& value_;
57 
58   public:
59     BOOST_THREAD_MOVABLE_ONLY( const_strict_lock_ptr )
60 
61     /**
62      * @param value constant reference of the value to protect.
63      * @param mtx reference to the mutex used to protect the value.
64      * @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value.
65      */
const_strict_lock_ptr(T const & val,Lockable & mtx)66     const_strict_lock_ptr(T const& val, Lockable & mtx) :
67       lk_(mtx), value_(val)
68     {
69     }
const_strict_lock_ptr(T const & val,Lockable & mtx,adopt_lock_t tag)70     const_strict_lock_ptr(T const& val, Lockable & mtx, adopt_lock_t tag) BOOST_NOEXCEPT :
71       lk_(mtx, tag), value_(val)
72     {
73     }
74     /**
75      * Move constructor.
76      * @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other.
77      */
const_strict_lock_ptr(BOOST_THREAD_RV_REF (const_strict_lock_ptr)other)78     const_strict_lock_ptr(BOOST_THREAD_RV_REF(const_strict_lock_ptr) other) BOOST_NOEXCEPT
79     : lk_(boost::move(BOOST_THREAD_RV(other).lk_)),value_(BOOST_THREAD_RV(other).value_)
80     {
81     }
82 
~const_strict_lock_ptr()83     ~const_strict_lock_ptr()
84     {
85     }
86 
87     /**
88      * @return a constant pointer to the protected value
89      */
operator ->() const90     const T* operator->() const
91     {
92       return &value_;
93     }
94 
95     /**
96      * @return a constant reference to the protected value
97      */
operator *() const98     const T& operator*() const
99     {
100       return value_;
101     }
102 
103   };
104 
105   /**
106    * strict lock providing a pointer access to the synchronized value type.
107    *
108    * @param T the value type.
109    * @param Lockable the mutex type protecting the value type.
110    */
111   template <typename T, typename Lockable = mutex>
112   class strict_lock_ptr : public const_strict_lock_ptr<T,Lockable>
113   {
114     typedef const_strict_lock_ptr<T,Lockable> base_type;
115   public:
116     BOOST_THREAD_MOVABLE_ONLY( strict_lock_ptr )
117 
118     /**
119      * @param value reference of the value to protect.
120      * @param mtx reference to the mutex used to protect the value.
121      * @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value.
122      */
strict_lock_ptr(T & val,Lockable & mtx)123     strict_lock_ptr(T & val, Lockable & mtx) :
124     base_type(val, mtx)
125     {
126     }
strict_lock_ptr(T & val,Lockable & mtx,adopt_lock_t tag)127     strict_lock_ptr(T & val, Lockable & mtx, adopt_lock_t tag) :
128     base_type(val, mtx, tag)
129     {
130     }
131 
132     /**
133      * Move constructor.
134      * @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other.
135      */
strict_lock_ptr(BOOST_THREAD_RV_REF (strict_lock_ptr)other)136     strict_lock_ptr(BOOST_THREAD_RV_REF(strict_lock_ptr) other)
137     : base_type(boost::move(static_cast<base_type&>(other)))
138     {
139     }
140 
~strict_lock_ptr()141     ~strict_lock_ptr()
142     {
143     }
144 
145     /**
146      * @return a pointer to the protected value
147      */
operator ->()148     T* operator->()
149     {
150       return const_cast<T*>(&this->value_);
151     }
152 
153     /**
154      * @return a reference to the protected value
155      */
operator *()156     T& operator*()
157     {
158       return const_cast<T&>(this->value_);
159     }
160 
161   };
162 
163   template <typename SV>
164   struct synchronized_value_strict_lock_ptr
165   {
166    typedef strict_lock_ptr<typename SV::value_type, typename SV::mutex_type> type;
167   };
168 
169   template <typename SV>
170   struct synchronized_value_strict_lock_ptr<const SV>
171   {
172    typedef const_strict_lock_ptr<typename SV::value_type, typename SV::mutex_type> type;
173   };
174   /**
175    * unique_lock providing a const pointer access to the synchronized value type.
176    *
177    * An object of type const_unique_lock_ptr is a unique_lock that provides a const pointer access to the synchronized value type.
178    * As unique_lock controls the ownership of a lockable object within a scope.
179    * Ownership of the lockable object may be acquired at construction or after construction,
180    * and may be transferred, after acquisition, to another const_unique_lock_ptr object.
181    * Objects of type const_unique_lock_ptr are not copyable but are movable.
182    * The behavior of a program is undefined if the mutex and the value type
183    * pointed do not exist for the entire remaining lifetime of the const_unique_lock_ptr object.
184    * The supplied Mutex type shall meet the BasicLockable requirements.
185    *
186    * @note const_unique_lock_ptr<T, Lockable> meets the Lockable requirements.
187    * If Lockable meets the TimedLockable requirements, const_unique_lock_ptr<T,Lockable>
188    * also meets the TimedLockable requirements.
189    *
190    * @param T the value type.
191    * @param Lockable the mutex type protecting the value type.
192    */
193   template <typename T, typename Lockable = mutex>
194   class const_unique_lock_ptr : public unique_lock<Lockable>
195   {
196     typedef unique_lock<Lockable> base_type;
197   public:
198     typedef T value_type;
199     typedef Lockable mutex_type;
200   protected:
201     T const& value_;
202 
203   public:
204     BOOST_THREAD_MOVABLE_ONLY(const_unique_lock_ptr)
205 
206     /**
207      * @param value reference of the value to protect.
208      * @param mtx reference to the mutex used to protect the value.
209      *
210      * @requires If mutex_type is not a recursive mutex the calling thread does not own the mutex.
211      *
212      * @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value.
213      */
const_unique_lock_ptr(T const & val,Lockable & mtx)214     const_unique_lock_ptr(T const& val, Lockable & mtx)
215     : base_type(mtx), value_(val)
216     {
217     }
218     /**
219      * @param value reference of the value to protect.
220      * @param mtx reference to the mutex used to protect the value.
221      * @param tag of type adopt_lock_t used to differentiate the constructor.
222      * @requires The calling thread own the mutex.
223      * @effects stores a reference to it and to the value type @c value taking ownership.
224      */
const_unique_lock_ptr(T const & val,Lockable & mtx,adopt_lock_t)225     const_unique_lock_ptr(T const& val, Lockable & mtx, adopt_lock_t) BOOST_NOEXCEPT
226     : base_type(mtx, adopt_lock), value_(val)
227     {
228     }
229     /**
230      * @param value reference of the value to protect.
231      * @param mtx reference to the mutex used to protect the value.
232      * @param tag of type defer_lock_t used to differentiate the constructor.
233      * @effects stores a reference to it and to the value type @c value c.
234      */
const_unique_lock_ptr(T const & val,Lockable & mtx,defer_lock_t)235     const_unique_lock_ptr(T const& val, Lockable & mtx, defer_lock_t) BOOST_NOEXCEPT
236     : base_type(mtx, defer_lock), value_(val)
237     {
238     }
239     /**
240      * @param value reference of the value to protect.
241      * @param mtx reference to the mutex used to protect the value.
242      * @param tag of type try_to_lock_t used to differentiate the constructor.
243      * @requires If mutex_type is not a recursive mutex the calling thread does not own the mutex.
244      * @effects try to lock the mutex @c mtx, stores a reference to it and to the value type @c value.
245      */
const_unique_lock_ptr(T const & val,Lockable & mtx,try_to_lock_t)246     const_unique_lock_ptr(T const& val, Lockable & mtx, try_to_lock_t) BOOST_NOEXCEPT
247     : base_type(mtx, try_to_lock), value_(val)
248     {
249     }
250     /**
251      * Move constructor.
252      * @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other.
253      */
const_unique_lock_ptr(BOOST_THREAD_RV_REF (const_unique_lock_ptr)other)254     const_unique_lock_ptr(BOOST_THREAD_RV_REF(const_unique_lock_ptr) other) BOOST_NOEXCEPT
255     : base_type(boost::move(static_cast<base_type&>(other))), value_(BOOST_THREAD_RV(other).value_)
256     {
257     }
258 
259     /**
260      * @effects If owns calls unlock() on the owned mutex.
261      */
~const_unique_lock_ptr()262     ~const_unique_lock_ptr()
263     {
264     }
265 
266     /**
267      * @return a constant pointer to the protected value
268      */
operator ->() const269     const T* operator->() const
270     {
271       BOOST_ASSERT (this->owns_lock());
272       return &value_;
273     }
274 
275     /**
276      * @return a constant reference to the protected value
277      */
operator *() const278     const T& operator*() const
279     {
280       BOOST_ASSERT (this->owns_lock());
281       return value_;
282     }
283 
284   };
285 
286   /**
287    * unique lock providing a pointer access to the synchronized value type.
288    *
289    * @param T the value type.
290    * @param Lockable the mutex type protecting the value type.
291    */
292   template <typename T, typename Lockable = mutex>
293   class unique_lock_ptr : public const_unique_lock_ptr<T, Lockable>
294   {
295     typedef const_unique_lock_ptr<T, Lockable> base_type;
296   public:
297     typedef T value_type;
298     typedef Lockable mutex_type;
299 
300     BOOST_THREAD_MOVABLE_ONLY(unique_lock_ptr)
301 
302     /**
303      * @param value reference of the value to protect.
304      * @param mtx reference to the mutex used to protect the value.
305      * @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value.
306      */
unique_lock_ptr(T & val,Lockable & mtx)307     unique_lock_ptr(T & val, Lockable & mtx)
308     : base_type(val, mtx)
309     {
310     }
311     /**
312      * @param value reference of the value to protect.
313      * @param mtx reference to the mutex used to protect the value.
314      * @param tag of type adopt_lock_t used to differentiate the constructor.
315      * @effects stores a reference to it and to the value type @c value taking ownership.
316      */
unique_lock_ptr(T & value,Lockable & mtx,adopt_lock_t)317     unique_lock_ptr(T & value, Lockable & mtx, adopt_lock_t) BOOST_NOEXCEPT
318     : base_type(value, mtx, adopt_lock)
319     {
320     }
321     /**
322      * @param value reference of the value to protect.
323      * @param mtx reference to the mutex used to protect the value.
324      * @param tag of type defer_lock_t used to differentiate the constructor.
325      * @effects stores a reference to it and to the value type @c value c.
326      */
unique_lock_ptr(T & value,Lockable & mtx,defer_lock_t)327     unique_lock_ptr(T & value, Lockable & mtx, defer_lock_t) BOOST_NOEXCEPT
328     : base_type(value, mtx, defer_lock)
329     {
330     }
331     /**
332      * @param value reference of the value to protect.
333      * @param mtx reference to the mutex used to protect the value.
334      * @param tag of type try_to_lock_t used to differentiate the constructor.
335      * @effects try to lock the mutex @c mtx, stores a reference to it and to the value type @c value.
336      */
unique_lock_ptr(T & value,Lockable & mtx,try_to_lock_t)337     unique_lock_ptr(T & value, Lockable & mtx, try_to_lock_t) BOOST_NOEXCEPT
338     : base_type(value, mtx, try_to_lock)
339     {
340     }
341     /**
342      * Move constructor.
343      * @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other.
344      */
unique_lock_ptr(BOOST_THREAD_RV_REF (unique_lock_ptr)other)345     unique_lock_ptr(BOOST_THREAD_RV_REF(unique_lock_ptr) other) BOOST_NOEXCEPT
346     : base_type(boost::move(static_cast<base_type&>(other)))
347     {
348     }
349 
~unique_lock_ptr()350     ~unique_lock_ptr()
351     {
352     }
353 
354     /**
355      * @return a pointer to the protected value
356      */
operator ->()357     T* operator->()
358     {
359       BOOST_ASSERT (this->owns_lock());
360       return const_cast<T*>(&this->value_);
361     }
362 
363     /**
364      * @return a reference to the protected value
365      */
operator *()366     T& operator*()
367     {
368       BOOST_ASSERT (this->owns_lock());
369       return const_cast<T&>(this->value_);
370     }
371 
372 
373   };
374 
375   template <typename SV>
376   struct synchronized_value_unique_lock_ptr
377   {
378    typedef unique_lock_ptr<typename SV::value_type, typename SV::mutex_type> type;
379   };
380 
381   template <typename SV>
382   struct synchronized_value_unique_lock_ptr<const SV>
383   {
384    typedef const_unique_lock_ptr<typename SV::value_type, typename SV::mutex_type> type;
385   };
386   /**
387    * cloaks a value type and the mutex used to protect it together.
388    * @param T the value type.
389    * @param Lockable the mutex type protecting the value type.
390    */
391   template <typename T, typename Lockable = mutex>
392   class synchronized_value
393   {
394 
395 #if ! defined(BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS)
396 #if ! defined BOOST_NO_CXX11_VARIADIC_TEMPLATES
397     template <typename ...SV>
398     friend std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> synchronize(SV& ...sv);
399 #else
400     template <typename SV1, typename SV2>
401     friend std::tuple<
402       typename synchronized_value_strict_lock_ptr<SV1>::type,
403       typename synchronized_value_strict_lock_ptr<SV2>::type
404     >
405     synchronize(SV1& sv1, SV2& sv2);
406     template <typename SV1, typename SV2, typename SV3>
407     friend std::tuple<
408       typename synchronized_value_strict_lock_ptr<SV1>::type,
409       typename synchronized_value_strict_lock_ptr<SV2>::type,
410       typename synchronized_value_strict_lock_ptr<SV3>::type
411     >
412     synchronize(SV1& sv1, SV2& sv2, SV3& sv3);
413 #endif
414 #endif
415 
416   public:
417     typedef T value_type;
418     typedef Lockable mutex_type;
419   private:
420     T value_;
421     mutable mutex_type mtx_;
422   public:
423     // construction/destruction
424     /**
425      * Default constructor.
426      *
427      * @Requires: T is DefaultConstructible
428      */
synchronized_value()429     synchronized_value()
430     //BOOST_NOEXCEPT_IF(is_nothrow_default_constructible<T>::value)
431     : value_()
432     {
433     }
434 
435     /**
436      * Constructor from copy constructible value.
437      *
438      * Requires: T is CopyConstructible
439      */
synchronized_value(T const & other)440     synchronized_value(T const& other)
441     //BOOST_NOEXCEPT_IF(is_nothrow_copy_constructible<T>::value)
442     : value_(other)
443     {
444     }
445 
446     /**
447      * Move Constructor.
448      *
449      * Requires: T is CopyMovable
450      */
synchronized_value(BOOST_THREAD_RV_REF (T)other)451     synchronized_value(BOOST_THREAD_RV_REF(T) other)
452     //BOOST_NOEXCEPT_IF(is_nothrow_move_constructible<T>::value)
453     : value_(boost::move(other))
454     {
455     }
456 
457     /**
458      * Constructor from value type.
459      *
460      * Requires: T is DefaultConstructible and Assignable
461      * Effects: Assigns the value on a scope protected by the mutex of the rhs. The mutex is not copied.
462      */
synchronized_value(synchronized_value const & rhs)463     synchronized_value(synchronized_value const& rhs)
464     {
465       strict_lock<mutex_type> lk(rhs.mtx_);
466       value_ = rhs.value_;
467     }
468 
469     /**
470      * Move Constructor from movable value type
471      *
472      */
synchronized_value(BOOST_THREAD_RV_REF (synchronized_value)other)473     synchronized_value(BOOST_THREAD_RV_REF(synchronized_value) other)
474     {
475       strict_lock<mutex_type> lk(BOOST_THREAD_RV(other).mtx_);
476       value_= boost::move(BOOST_THREAD_RV(other).value_);
477     }
478 
479     // mutation
480     /**
481      * Assignment operator.
482      *
483      * Effects: Copies the underlying value on a scope protected by the two mutexes.
484      * The mutex is not copied. The locks are acquired using lock, so deadlock is avoided.
485      * For example, there is no problem if one thread assigns a = b and the other assigns b = a.
486      *
487      * Return: *this
488      */
489 
operator =(synchronized_value const & rhs)490     synchronized_value& operator=(synchronized_value const& rhs)
491     {
492       if(&rhs != this)
493       {
494         // auto _ = make_unique_locks(mtx_, rhs.mtx_);
495         unique_lock<mutex_type> lk1(mtx_, defer_lock);
496         unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
497         lock(lk1,lk2);
498 
499         value_ = rhs.value_;
500       }
501       return *this;
502     }
503     /**
504      * Assignment operator from a T const&.
505      * Effects: The operator copies the value on a scope protected by the mutex.
506      * Return: *this
507      */
operator =(value_type const & val)508     synchronized_value& operator=(value_type const& val)
509     {
510       {
511         strict_lock<mutex_type> lk(mtx_);
512         value_ = val;
513       }
514       return *this;
515     }
516 
517     //observers
518     /**
519      * Explicit conversion to value type.
520      *
521      * Requires: T is CopyConstructible
522      * Return: A copy of the protected value obtained on a scope protected by the mutex.
523      *
524      */
get() const525     T get() const
526     {
527       strict_lock<mutex_type> lk(mtx_);
528       return value_;
529     }
530     /**
531      * Explicit conversion to value type.
532      *
533      * Requires: T is CopyConstructible
534      * Return: A copy of the protected value obtained on a scope protected by the mutex.
535      *
536      */
537 #if ! defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
operator T() const538     explicit operator T() const
539     {
540       return get();
541     }
542 #endif
543 
544     /**
545      * value type getter.
546      *
547      * Return: A constant reference to the protected value.
548      *
549      * Note: Not thread safe
550      *
551      */
value() const552     T const& value() const
553     {
554       return value_;
555     }
556     /**
557      * mutex getter.
558      *
559      * Return: A constant reference to the protecting mutex.
560      *
561      * Note: Not thread safe
562      *
563      */
mutex() const564     mutex_type const& mutex() const
565     {
566       return mtx_;
567     }
568     /**
569      * Swap
570      *
571      * Effects: Swaps the data. Again, locks are acquired using lock(). The mutexes are not swapped.
572      * A swap method accepts a T& and swaps the data inside a critical section.
573      * This is by far the preferred method of changing the guarded datum wholesale because it keeps the lock only
574      * for a short time, thus lowering the pressure on the mutex.
575      */
swap(synchronized_value & rhs)576     void swap(synchronized_value & rhs)
577     {
578       if (this == &rhs) {
579         return;
580       }
581       // auto _ = make_unique_locks(mtx_, rhs.mtx_);
582       unique_lock<mutex_type> lk1(mtx_, defer_lock);
583       unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
584       lock(lk1,lk2);
585       boost::swap(value_, rhs.value_);
586     }
587     /**
588      * Swap with the underlying value type
589      *
590      * Effects: Swaps the data on a scope protected by the mutex.
591      */
swap(value_type & rhs)592     void swap(value_type & rhs)
593     {
594       strict_lock<mutex_type> lk(mtx_);
595       boost::swap(value_, rhs);
596     }
597 
598     /**
599      * Essentially calling a method obj->foo(x, y, z) calls the method foo(x, y, z) inside a critical section as
600      * long-lived as the call itself.
601      */
operator ->()602     strict_lock_ptr<T,Lockable> operator->()
603     {
604       return BOOST_THREAD_MAKE_RV_REF((strict_lock_ptr<T,Lockable>(value_, mtx_)));
605     }
606     /**
607      * If the synchronized_value object involved is const-qualified, then you'll only be able to call const methods
608      * through operator->. So, for example, vec->push_back("xyz") won't work if vec were const-qualified.
609      * The locking mechanism capitalizes on the assumption that const methods don't modify their underlying data.
610      */
operator ->() const611     const_strict_lock_ptr<T,Lockable> operator->() const
612     {
613       return BOOST_THREAD_MAKE_RV_REF((const_strict_lock_ptr<T,Lockable>(value_, mtx_)));
614     }
615 
616     /**
617      * Call function on a locked block.
618      *
619      * @requires fct(value_) is well formed.
620      *
621      * Example
622      *   void fun(synchronized_value<vector<int>> & v) {
623      *     v ( [](vector<int>> & vec)
624      *     {
625      *       vec.push_back(42);
626      *       assert(vec.back() == 42);
627      *     } );
628      *   }
629      */
630     template <typename F>
631     inline
632     typename boost::result_of<F(value_type&)>::type
operator ()(BOOST_THREAD_RV_REF (F)fct)633     operator()(BOOST_THREAD_RV_REF(F) fct)
634     {
635       strict_lock<mutex_type> lk(mtx_);
636       return fct(value_);
637     }
638     template <typename F>
639     inline
640     typename boost::result_of<F(value_type const&)>::type
operator ()(BOOST_THREAD_RV_REF (F)fct) const641     operator()(BOOST_THREAD_RV_REF(F) fct) const
642     {
643       strict_lock<mutex_type> lk(mtx_);
644       return fct(value_);
645     }
646 
647 
648 #if defined  BOOST_NO_CXX11_RVALUE_REFERENCES
649     template <typename F>
650     inline
651     typename boost::result_of<F(value_type&)>::type
operator ()(F const & fct)652     operator()(F const & fct)
653     {
654       strict_lock<mutex_type> lk(mtx_);
655       return fct(value_);
656     }
657     template <typename F>
658     inline
659     typename boost::result_of<F(value_type const&)>::type
operator ()(F const & fct) const660     operator()(F const & fct) const
661     {
662       strict_lock<mutex_type> lk(mtx_);
663       return fct(value_);
664     }
665 
666     template <typename R>
667     inline
operator ()(R (* fct)(value_type &))668     R operator()(R(*fct)(value_type&))
669     {
670       strict_lock<mutex_type> lk(mtx_);
671       return fct(value_);
672     }
673     template <typename R>
674     inline
operator ()(R (* fct)(value_type const &)) const675     R operator()(R(*fct)(value_type const&)) const
676     {
677       strict_lock<mutex_type> lk(mtx_);
678       return fct(value_);
679     }
680 #endif
681 
682 
683     /**
684      * The synchronize() factory make easier to lock on a scope.
685      * As discussed, operator-> can only lock over the duration of a call, so it is insufficient for complex operations.
686      * With synchronize() you get to lock the object in a scoped and to directly access the object inside that scope.
687      *
688      * Example
689      *   void fun(synchronized_value<vector<int>> & v) {
690      *     auto&& vec=v.synchronize();
691      *     vec.push_back(42);
692      *     assert(vec.back() == 42);
693      *   }
694      */
synchronize()695     strict_lock_ptr<T,Lockable> synchronize()
696     {
697       return BOOST_THREAD_MAKE_RV_REF((strict_lock_ptr<T,Lockable>(value_, mtx_)));
698     }
synchronize() const699     const_strict_lock_ptr<T,Lockable> synchronize() const
700     {
701       return BOOST_THREAD_MAKE_RV_REF((const_strict_lock_ptr<T,Lockable>(value_, mtx_)));
702     }
703 
unique_synchronize()704     unique_lock_ptr<T,Lockable> unique_synchronize()
705     {
706       return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_)));
707     }
unique_synchronize() const708     const_unique_lock_ptr<T,Lockable> unique_synchronize() const
709     {
710       return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_)));
711     }
unique_synchronize(defer_lock_t tag)712     unique_lock_ptr<T,Lockable> unique_synchronize(defer_lock_t tag)
713     {
714       return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_, tag)));
715     }
unique_synchronize(defer_lock_t tag) const716     const_unique_lock_ptr<T,Lockable> unique_synchronize(defer_lock_t tag) const
717     {
718       return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_, tag)));
719     }
defer_synchronize()720     unique_lock_ptr<T,Lockable> defer_synchronize() BOOST_NOEXCEPT
721     {
722       return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_, defer_lock)));
723     }
defer_synchronize() const724     const_unique_lock_ptr<T,Lockable> defer_synchronize() const BOOST_NOEXCEPT
725     {
726       return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_, defer_lock)));
727     }
try_to_synchronize()728     unique_lock_ptr<T,Lockable> try_to_synchronize() BOOST_NOEXCEPT
729     {
730       return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_, try_to_lock)));
731     }
try_to_synchronize() const732     const_unique_lock_ptr<T,Lockable> try_to_synchronize() const BOOST_NOEXCEPT
733     {
734       return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_, try_to_lock)));
735     }
adopt_synchronize()736     unique_lock_ptr<T,Lockable> adopt_synchronize() BOOST_NOEXCEPT
737     {
738       return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_, adopt_lock)));
739     }
adopt_synchronize() const740     const_unique_lock_ptr<T,Lockable> adopt_synchronize() const BOOST_NOEXCEPT
741     {
742       return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_, adopt_lock)));
743     }
744 
745 
746 #if ! defined __IBMCPP__
747     private:
748 #endif
749     class deref_value
750     {
751     private:
752       friend class synchronized_value;
753 
754       boost::unique_lock<mutex_type> lk_;
755       T& value_;
756 
deref_value(synchronized_value & outer)757       explicit deref_value(synchronized_value& outer):
758       lk_(outer.mtx_),value_(outer.value_)
759       {}
760 
761     public:
762       BOOST_THREAD_MOVABLE_ONLY(deref_value)
763 
deref_value(BOOST_THREAD_RV_REF (deref_value)other)764       deref_value(BOOST_THREAD_RV_REF(deref_value) other):
765       lk_(boost::move(BOOST_THREAD_RV(other).lk_)),value_(BOOST_THREAD_RV(other).value_)
766       {}
operator T&()767       operator T&()
768       {
769         return value_;
770       }
771 
operator =(T const & newVal)772       deref_value& operator=(T const& newVal)
773       {
774         value_=newVal;
775         return *this;
776       }
777     };
778     class const_deref_value
779     {
780     private:
781       friend class synchronized_value;
782 
783       boost::unique_lock<mutex_type> lk_;
784       const T& value_;
785 
const_deref_value(synchronized_value const & outer)786       explicit const_deref_value(synchronized_value const& outer):
787       lk_(outer.mtx_), value_(outer.value_)
788       {}
789 
790     public:
791       BOOST_THREAD_MOVABLE_ONLY(const_deref_value)
792 
const_deref_value(BOOST_THREAD_RV_REF (const_deref_value)other)793       const_deref_value(BOOST_THREAD_RV_REF(const_deref_value) other):
794       lk_(boost::move(BOOST_THREAD_RV(other).lk_)), value_(BOOST_THREAD_RV(other).value_)
795       {}
796 
operator const T&()797       operator const T&()
798       {
799         return value_;
800       }
801     };
802 
803   public:
operator *()804     deref_value operator*()
805     {
806       return BOOST_THREAD_MAKE_RV_REF(deref_value(*this));
807     }
808 
operator *() const809     const_deref_value operator*() const
810     {
811       return BOOST_THREAD_MAKE_RV_REF(const_deref_value(*this));
812     }
813 
814     // io functions
815     /**
816      * @requires T is OutputStreamable
817      * @effects saves the value type on the output stream @c os.
818      */
819     template <typename OStream>
save(OStream & os) const820     void save(OStream& os) const
821     {
822       strict_lock<mutex_type> lk(mtx_);
823       os << value_;
824     }
825     /**
826      * @requires T is InputStreamable
827      * @effects loads the value type from the input stream @c is.
828      */
829     template <typename IStream>
load(IStream & is)830     void load(IStream& is)
831     {
832       strict_lock<mutex_type> lk(mtx_);
833       is >> value_;
834     }
835 
836     // relational operators
837     /**
838      * @requires T is EqualityComparable
839      *
840      */
operator ==(synchronized_value const & rhs) const841     bool operator==(synchronized_value const& rhs)  const
842     {
843       unique_lock<mutex_type> lk1(mtx_, defer_lock);
844       unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
845       lock(lk1,lk2);
846 
847       return value_ == rhs.value_;
848     }
849     /**
850      * @requires T is LessThanComparable
851      *
852      */
operator <(synchronized_value const & rhs) const853     bool operator<(synchronized_value const& rhs) const
854     {
855       unique_lock<mutex_type> lk1(mtx_, defer_lock);
856       unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
857       lock(lk1,lk2);
858 
859       return value_ < rhs.value_;
860     }
861     /**
862      * @requires T is GreaterThanComparable
863      *
864      */
operator >(synchronized_value const & rhs) const865     bool operator>(synchronized_value const& rhs) const
866     {
867       unique_lock<mutex_type> lk1(mtx_, defer_lock);
868       unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
869       lock(lk1,lk2);
870 
871       return value_ > rhs.value_;
872     }
operator <=(synchronized_value const & rhs) const873     bool operator<=(synchronized_value const& rhs) const
874     {
875       unique_lock<mutex_type> lk1(mtx_, defer_lock);
876       unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
877       lock(lk1,lk2);
878 
879       return value_ <= rhs.value_;
880     }
operator >=(synchronized_value const & rhs) const881     bool operator>=(synchronized_value const& rhs) const
882     {
883       unique_lock<mutex_type> lk1(mtx_, defer_lock);
884       unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
885       lock(lk1,lk2);
886 
887       return value_ >= rhs.value_;
888     }
operator ==(value_type const & rhs) const889     bool operator==(value_type const& rhs) const
890     {
891       unique_lock<mutex_type> lk1(mtx_);
892 
893       return value_ == rhs;
894     }
operator !=(value_type const & rhs) const895     bool operator!=(value_type const& rhs) const
896     {
897       unique_lock<mutex_type> lk1(mtx_);
898 
899       return value_ != rhs;
900     }
operator <(value_type const & rhs) const901     bool operator<(value_type const& rhs) const
902     {
903       unique_lock<mutex_type> lk1(mtx_);
904 
905       return value_ < rhs;
906     }
operator <=(value_type const & rhs) const907     bool operator<=(value_type const& rhs) const
908     {
909       unique_lock<mutex_type> lk1(mtx_);
910 
911       return value_ <= rhs;
912     }
operator >(value_type const & rhs) const913     bool operator>(value_type const& rhs) const
914     {
915       unique_lock<mutex_type> lk1(mtx_);
916 
917       return value_ > rhs;
918     }
operator >=(value_type const & rhs) const919     bool operator>=(value_type const& rhs) const
920     {
921       unique_lock<mutex_type> lk1(mtx_);
922 
923       return value_ >= rhs;
924     }
925 
926   };
927 
928   // Specialized algorithms
929   /**
930    *
931    */
932   template <typename T, typename L>
swap(synchronized_value<T,L> & lhs,synchronized_value<T,L> & rhs)933   inline void swap(synchronized_value<T,L> & lhs, synchronized_value<T,L> & rhs)
934   {
935     lhs.swap(rhs);
936   }
937   template <typename T, typename L>
swap(synchronized_value<T,L> & lhs,T & rhs)938   inline void swap(synchronized_value<T,L> & lhs, T & rhs)
939   {
940     lhs.swap(rhs);
941   }
942   template <typename T, typename L>
swap(T & lhs,synchronized_value<T,L> & rhs)943   inline void swap(T & lhs, synchronized_value<T,L> & rhs)
944   {
945     rhs.swap(lhs);
946   }
947 
948   //Hash support
949 
950 //  template <class T> struct hash;
951 //  template <typename T, typename L>
952 //  struct hash<synchronized_value<T,L> >;
953 
954   // Comparison with T
955   template <typename T, typename L>
operator !=(synchronized_value<T,L> const & lhs,synchronized_value<T,L> const & rhs)956   bool operator!=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
957   {
958     return ! (lhs==rhs);
959   }
960 
961   template <typename T, typename L>
operator ==(T const & lhs,synchronized_value<T,L> const & rhs)962   bool operator==(T const& lhs, synchronized_value<T,L> const&rhs)
963   {
964     return rhs==lhs;
965   }
966   template <typename T, typename L>
operator !=(T const & lhs,synchronized_value<T,L> const & rhs)967   bool operator!=(T const& lhs, synchronized_value<T,L> const&rhs)
968   {
969     return rhs!=lhs;
970   }
971   template <typename T, typename L>
operator <(T const & lhs,synchronized_value<T,L> const & rhs)972   bool operator<(T const& lhs, synchronized_value<T,L> const&rhs)
973   {
974     return rhs>lhs;
975   }
976   template <typename T, typename L>
operator <=(T const & lhs,synchronized_value<T,L> const & rhs)977   bool operator<=(T const& lhs, synchronized_value<T,L> const&rhs)
978   {
979     return rhs>=lhs;
980   }
981   template <typename T, typename L>
operator >(T const & lhs,synchronized_value<T,L> const & rhs)982   bool operator>(T const& lhs, synchronized_value<T,L> const&rhs)
983   {
984     return rhs<lhs;
985   }
986   template <typename T, typename L>
operator >=(T const & lhs,synchronized_value<T,L> const & rhs)987   bool operator>=(T const& lhs, synchronized_value<T,L> const&rhs)
988   {
989     return rhs<=lhs;
990   }
991 
992   /**
993    *
994    */
995   template <typename OStream, typename T, typename L>
operator <<(OStream & os,synchronized_value<T,L> const & rhs)996   inline OStream& operator<<(OStream& os, synchronized_value<T,L> const& rhs)
997   {
998     rhs.save(os);
999     return os;
1000   }
1001   template <typename IStream, typename T, typename L>
operator >>(IStream & is,synchronized_value<T,L> & rhs)1002   inline IStream& operator>>(IStream& is, synchronized_value<T,L>& rhs)
1003   {
1004     rhs.load(is);
1005     return is;
1006   }
1007 
1008 #if ! defined(BOOST_THREAD_NO_SYNCHRONIZE)
1009 #if ! defined BOOST_NO_CXX11_VARIADIC_TEMPLATES
1010 
1011   template <typename ...SV>
synchronize(SV &...sv)1012   std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> synchronize(SV& ...sv)
1013   {
1014     boost::lock(sv.mtx_ ...);
1015     typedef std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> t_type;
1016 
1017     return t_type(typename synchronized_value_strict_lock_ptr<SV>::type(sv.value_, sv.mtx_, adopt_lock) ...);
1018   }
1019 #else
1020 
1021   template <typename SV1, typename SV2>
1022   std::tuple<
1023     typename synchronized_value_strict_lock_ptr<SV1>::type,
1024     typename synchronized_value_strict_lock_ptr<SV2>::type
1025   >
synchronize(SV1 & sv1,SV2 & sv2)1026   synchronize(SV1& sv1, SV2& sv2)
1027   {
1028     boost::lock(sv1.mtx_, sv2.mtx_);
1029     typedef std::tuple<
1030         typename synchronized_value_strict_lock_ptr<SV1>::type,
1031         typename synchronized_value_strict_lock_ptr<SV2>::type
1032         > t_type;
1033 
1034     return t_type(
1035         typename synchronized_value_strict_lock_ptr<SV1>::type(sv1.value_, sv1.mtx_, adopt_lock),
1036         typename synchronized_value_strict_lock_ptr<SV2>::type(sv2.value_, sv2.mtx_, adopt_lock)
1037         );
1038 
1039   }
1040   template <typename SV1, typename SV2, typename SV3>
1041   std::tuple<
1042     typename synchronized_value_strict_lock_ptr<SV1>::type,
1043     typename synchronized_value_strict_lock_ptr<SV2>::type,
1044     typename synchronized_value_strict_lock_ptr<SV3>::type
1045   >
synchronize(SV1 & sv1,SV2 & sv2,SV3 & sv3)1046   synchronize(SV1& sv1, SV2& sv2, SV3& sv3)
1047   {
1048     boost::lock(sv1.mtx_, sv2.mtx_);
1049     typedef std::tuple<
1050         typename synchronized_value_strict_lock_ptr<SV1>::type,
1051         typename synchronized_value_strict_lock_ptr<SV2>::type,
1052         typename synchronized_value_strict_lock_ptr<SV3>::type
1053         > t_type;
1054 
1055     return t_type(
1056         typename synchronized_value_strict_lock_ptr<SV1>::type(sv1.value_, sv1.mtx_, adopt_lock),
1057         typename synchronized_value_strict_lock_ptr<SV2>::type(sv2.value_, sv2.mtx_, adopt_lock),
1058         typename synchronized_value_strict_lock_ptr<SV3>::type(sv3.value_, sv3.mtx_, adopt_lock)
1059         );
1060 
1061   }
1062 #endif
1063 #endif
1064 }
1065 
1066 #include <boost/config/abi_suffix.hpp>
1067 
1068 #endif // header
1069