Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-15 10:09:31

0001 // (C) Copyright 2010 Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
0002 // (C) Copyright 2012 Vicente J. Botet Escriba
0003 // Distributed under the Boost Software License, Version 1.0. (See
0004 // accompanying file LICENSE_1_0.txt or copy at
0005 // http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 
0008 #ifndef BOOST_THREAD_SYNCHRONIZED_VALUE_HPP
0009 #define BOOST_THREAD_SYNCHRONIZED_VALUE_HPP
0010 
0011 #include <boost/thread/detail/config.hpp>
0012 
0013 #include <boost/thread/detail/move.hpp>
0014 #include <boost/thread/mutex.hpp>
0015 #include <boost/thread/lock_types.hpp>
0016 #include <boost/thread/lock_guard.hpp>
0017 #include <boost/thread/lock_algorithms.hpp>
0018 #include <boost/thread/lock_factories.hpp>
0019 #include <boost/thread/strict_lock.hpp>
0020 #include <boost/core/invoke_swap.hpp>
0021 #include <boost/type_traits/declval.hpp>
0022 //#include <boost/type_traits.hpp>
0023 //#include <boost/thread/detail/is_nothrow_default_constructible.hpp>
0024 //#if ! defined BOOST_NO_CXX11_HDR_TYPE_TRAITS
0025 //#include <type_traits>
0026 //#endif
0027 
0028 #if ! defined(BOOST_THREAD_NO_SYNCHRONIZE)
0029 #include <tuple> // todo change to <boost/tuple.hpp> once Boost.Tuple or Boost.Fusion provides Move semantics on C++98 compilers.
0030 #include <functional>
0031 #endif
0032 
0033 #include <boost/utility/result_of.hpp>
0034 
0035 #include <boost/config/abi_prefix.hpp>
0036 
0037 namespace boost
0038 {
0039 
0040   /**
0041    * strict lock providing a const pointer access to the synchronized value type.
0042    *
0043    * @param T the value type.
0044    * @param Lockable the mutex type protecting the value type.
0045    */
0046   template <typename T, typename Lockable = mutex>
0047   class const_strict_lock_ptr
0048   {
0049   public:
0050     typedef T value_type;
0051     typedef Lockable mutex_type;
0052   protected:
0053 
0054     // this should be a strict_lock, but unique_lock is needed to be able to return it.
0055     boost::unique_lock<mutex_type> lk_;
0056     T const& value_;
0057 
0058   public:
0059     BOOST_THREAD_MOVABLE_ONLY( const_strict_lock_ptr )
0060 
0061     /**
0062      * @param value constant reference of the value to protect.
0063      * @param mtx reference to the mutex used to protect the value.
0064      * @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value.
0065      */
0066     const_strict_lock_ptr(T const& val, Lockable & mtx) :
0067       lk_(mtx), value_(val)
0068     {
0069     }
0070     const_strict_lock_ptr(T const& val, Lockable & mtx, adopt_lock_t tag) BOOST_NOEXCEPT :
0071       lk_(mtx, tag), value_(val)
0072     {
0073     }
0074     /**
0075      * Move constructor.
0076      * @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other.
0077      */
0078     const_strict_lock_ptr(BOOST_THREAD_RV_REF(const_strict_lock_ptr) other) BOOST_NOEXCEPT
0079     : lk_(boost::move(BOOST_THREAD_RV(other).lk_)),value_(BOOST_THREAD_RV(other).value_)
0080     {
0081     }
0082 
0083     ~const_strict_lock_ptr()
0084     {
0085     }
0086 
0087     /**
0088      * @return a constant pointer to the protected value
0089      */
0090     const T* operator->() const
0091     {
0092       return &value_;
0093     }
0094 
0095     /**
0096      * @return a constant reference to the protected value
0097      */
0098     const T& operator*() const
0099     {
0100       return value_;
0101     }
0102 
0103   };
0104 
0105   /**
0106    * strict lock providing a pointer access to the synchronized value type.
0107    *
0108    * @param T the value type.
0109    * @param Lockable the mutex type protecting the value type.
0110    */
0111   template <typename T, typename Lockable = mutex>
0112   class strict_lock_ptr : public const_strict_lock_ptr<T,Lockable>
0113   {
0114     typedef const_strict_lock_ptr<T,Lockable> base_type;
0115   public:
0116     BOOST_THREAD_MOVABLE_ONLY( strict_lock_ptr )
0117 
0118     /**
0119      * @param value reference of the value to protect.
0120      * @param mtx reference to the mutex used to protect the value.
0121      * @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value.
0122      */
0123     strict_lock_ptr(T & val, Lockable & mtx) :
0124     base_type(val, mtx)
0125     {
0126     }
0127     strict_lock_ptr(T & val, Lockable & mtx, adopt_lock_t tag) :
0128     base_type(val, mtx, tag)
0129     {
0130     }
0131 
0132     /**
0133      * Move constructor.
0134      * @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other.
0135      */
0136     strict_lock_ptr(BOOST_THREAD_RV_REF(strict_lock_ptr) other)
0137     : base_type(boost::move(static_cast<base_type&>(other)))
0138     {
0139     }
0140 
0141     ~strict_lock_ptr()
0142     {
0143     }
0144 
0145     /**
0146      * @return a pointer to the protected value
0147      */
0148     T* operator->()
0149     {
0150       return const_cast<T*>(&this->value_);
0151     }
0152 
0153     /**
0154      * @return a reference to the protected value
0155      */
0156     T& operator*()
0157     {
0158       return const_cast<T&>(this->value_);
0159     }
0160 
0161   };
0162 
0163   template <typename SV>
0164   struct synchronized_value_strict_lock_ptr
0165   {
0166    typedef strict_lock_ptr<typename SV::value_type, typename SV::mutex_type> type;
0167   };
0168 
0169   template <typename SV>
0170   struct synchronized_value_strict_lock_ptr<const SV>
0171   {
0172    typedef const_strict_lock_ptr<typename SV::value_type, typename SV::mutex_type> type;
0173   };
0174   /**
0175    * unique_lock providing a const pointer access to the synchronized value type.
0176    *
0177    * An object of type const_unique_lock_ptr is a unique_lock that provides a const pointer access to the synchronized value type.
0178    * As unique_lock controls the ownership of a lockable object within a scope.
0179    * Ownership of the lockable object may be acquired at construction or after construction,
0180    * and may be transferred, after acquisition, to another const_unique_lock_ptr object.
0181    * Objects of type const_unique_lock_ptr are not copyable but are movable.
0182    * The behavior of a program is undefined if the mutex and the value type
0183    * pointed do not exist for the entire remaining lifetime of the const_unique_lock_ptr object.
0184    * The supplied Mutex type shall meet the BasicLockable requirements.
0185    *
0186    * @note const_unique_lock_ptr<T, Lockable> meets the Lockable requirements.
0187    * If Lockable meets the TimedLockable requirements, const_unique_lock_ptr<T,Lockable>
0188    * also meets the TimedLockable requirements.
0189    *
0190    * @param T the value type.
0191    * @param Lockable the mutex type protecting the value type.
0192    */
0193   template <typename T, typename Lockable = mutex>
0194   class const_unique_lock_ptr : public unique_lock<Lockable>
0195   {
0196     typedef unique_lock<Lockable> base_type;
0197   public:
0198     typedef T value_type;
0199     typedef Lockable mutex_type;
0200   protected:
0201     T const& value_;
0202 
0203   public:
0204     BOOST_THREAD_MOVABLE_ONLY(const_unique_lock_ptr)
0205 
0206     /**
0207      * @param value reference of the value to protect.
0208      * @param mtx reference to the mutex used to protect the value.
0209      *
0210      * @requires If mutex_type is not a recursive mutex the calling thread does not own the mutex.
0211      *
0212      * @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value.
0213      */
0214     const_unique_lock_ptr(T const& val, Lockable & mtx)
0215     : base_type(mtx), value_(val)
0216     {
0217     }
0218     /**
0219      * @param value reference of the value to protect.
0220      * @param mtx reference to the mutex used to protect the value.
0221      * @param tag of type adopt_lock_t used to differentiate the constructor.
0222      * @requires The calling thread own the mutex.
0223      * @effects stores a reference to it and to the value type @c value taking ownership.
0224      */
0225     const_unique_lock_ptr(T const& val, Lockable & mtx, adopt_lock_t) BOOST_NOEXCEPT
0226     : base_type(mtx, adopt_lock), value_(val)
0227     {
0228     }
0229     /**
0230      * @param value reference of the value to protect.
0231      * @param mtx reference to the mutex used to protect the value.
0232      * @param tag of type defer_lock_t used to differentiate the constructor.
0233      * @effects stores a reference to it and to the value type @c value c.
0234      */
0235     const_unique_lock_ptr(T const& val, Lockable & mtx, defer_lock_t) BOOST_NOEXCEPT
0236     : base_type(mtx, defer_lock), value_(val)
0237     {
0238     }
0239     /**
0240      * @param value reference of the value to protect.
0241      * @param mtx reference to the mutex used to protect the value.
0242      * @param tag of type try_to_lock_t used to differentiate the constructor.
0243      * @requires If mutex_type is not a recursive mutex the calling thread does not own the mutex.
0244      * @effects try to lock the mutex @c mtx, stores a reference to it and to the value type @c value.
0245      */
0246     const_unique_lock_ptr(T const& val, Lockable & mtx, try_to_lock_t) BOOST_NOEXCEPT
0247     : base_type(mtx, try_to_lock), value_(val)
0248     {
0249     }
0250     /**
0251      * Move constructor.
0252      * @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other.
0253      */
0254     const_unique_lock_ptr(BOOST_THREAD_RV_REF(const_unique_lock_ptr) other) BOOST_NOEXCEPT
0255     : base_type(boost::move(static_cast<base_type&>(other))), value_(BOOST_THREAD_RV(other).value_)
0256     {
0257     }
0258 
0259     /**
0260      * @effects If owns calls unlock() on the owned mutex.
0261      */
0262     ~const_unique_lock_ptr()
0263     {
0264     }
0265 
0266     /**
0267      * @return a constant pointer to the protected value
0268      */
0269     const T* operator->() const
0270     {
0271       BOOST_ASSERT (this->owns_lock());
0272       return &value_;
0273     }
0274 
0275     /**
0276      * @return a constant reference to the protected value
0277      */
0278     const T& operator*() const
0279     {
0280       BOOST_ASSERT (this->owns_lock());
0281       return value_;
0282     }
0283 
0284   };
0285 
0286   /**
0287    * unique lock providing a pointer access to the synchronized value type.
0288    *
0289    * @param T the value type.
0290    * @param Lockable the mutex type protecting the value type.
0291    */
0292   template <typename T, typename Lockable = mutex>
0293   class unique_lock_ptr : public const_unique_lock_ptr<T, Lockable>
0294   {
0295     typedef const_unique_lock_ptr<T, Lockable> base_type;
0296   public:
0297     typedef T value_type;
0298     typedef Lockable mutex_type;
0299 
0300     BOOST_THREAD_MOVABLE_ONLY(unique_lock_ptr)
0301 
0302     /**
0303      * @param value reference of the value to protect.
0304      * @param mtx reference to the mutex used to protect the value.
0305      * @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value.
0306      */
0307     unique_lock_ptr(T & val, Lockable & mtx)
0308     : base_type(val, mtx)
0309     {
0310     }
0311     /**
0312      * @param value reference of the value to protect.
0313      * @param mtx reference to the mutex used to protect the value.
0314      * @param tag of type adopt_lock_t used to differentiate the constructor.
0315      * @effects stores a reference to it and to the value type @c value taking ownership.
0316      */
0317     unique_lock_ptr(T & value, Lockable & mtx, adopt_lock_t) BOOST_NOEXCEPT
0318     : base_type(value, mtx, adopt_lock)
0319     {
0320     }
0321     /**
0322      * @param value reference of the value to protect.
0323      * @param mtx reference to the mutex used to protect the value.
0324      * @param tag of type defer_lock_t used to differentiate the constructor.
0325      * @effects stores a reference to it and to the value type @c value c.
0326      */
0327     unique_lock_ptr(T & value, Lockable & mtx, defer_lock_t) BOOST_NOEXCEPT
0328     : base_type(value, mtx, defer_lock)
0329     {
0330     }
0331     /**
0332      * @param value reference of the value to protect.
0333      * @param mtx reference to the mutex used to protect the value.
0334      * @param tag of type try_to_lock_t used to differentiate the constructor.
0335      * @effects try to lock the mutex @c mtx, stores a reference to it and to the value type @c value.
0336      */
0337     unique_lock_ptr(T & value, Lockable & mtx, try_to_lock_t) BOOST_NOEXCEPT
0338     : base_type(value, mtx, try_to_lock)
0339     {
0340     }
0341     /**
0342      * Move constructor.
0343      * @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other.
0344      */
0345     unique_lock_ptr(BOOST_THREAD_RV_REF(unique_lock_ptr) other) BOOST_NOEXCEPT
0346     : base_type(boost::move(static_cast<base_type&>(other)))
0347     {
0348     }
0349 
0350     ~unique_lock_ptr()
0351     {
0352     }
0353 
0354     /**
0355      * @return a pointer to the protected value
0356      */
0357     T* operator->()
0358     {
0359       BOOST_ASSERT (this->owns_lock());
0360       return const_cast<T*>(&this->value_);
0361     }
0362 
0363     /**
0364      * @return a reference to the protected value
0365      */
0366     T& operator*()
0367     {
0368       BOOST_ASSERT (this->owns_lock());
0369       return const_cast<T&>(this->value_);
0370     }
0371 
0372 
0373   };
0374 
0375   template <typename SV>
0376   struct synchronized_value_unique_lock_ptr
0377   {
0378    typedef unique_lock_ptr<typename SV::value_type, typename SV::mutex_type> type;
0379   };
0380 
0381   template <typename SV>
0382   struct synchronized_value_unique_lock_ptr<const SV>
0383   {
0384    typedef const_unique_lock_ptr<typename SV::value_type, typename SV::mutex_type> type;
0385   };
0386   /**
0387    * cloaks a value type and the mutex used to protect it together.
0388    * @param T the value type.
0389    * @param Lockable the mutex type protecting the value type.
0390    */
0391   template <typename T, typename Lockable = mutex>
0392   class synchronized_value
0393   {
0394 
0395 #if ! defined(BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS)
0396 #if ! defined BOOST_NO_CXX11_VARIADIC_TEMPLATES
0397     template <typename ...SV>
0398     friend std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> synchronize(SV& ...sv);
0399 #else
0400     template <typename SV1, typename SV2>
0401     friend std::tuple<
0402       typename synchronized_value_strict_lock_ptr<SV1>::type,
0403       typename synchronized_value_strict_lock_ptr<SV2>::type
0404     >
0405     synchronize(SV1& sv1, SV2& sv2);
0406     template <typename SV1, typename SV2, typename SV3>
0407     friend std::tuple<
0408       typename synchronized_value_strict_lock_ptr<SV1>::type,
0409       typename synchronized_value_strict_lock_ptr<SV2>::type,
0410       typename synchronized_value_strict_lock_ptr<SV3>::type
0411     >
0412     synchronize(SV1& sv1, SV2& sv2, SV3& sv3);
0413 #endif
0414 #endif
0415 
0416   public:
0417     typedef T value_type;
0418     typedef Lockable mutex_type;
0419   private:
0420     T value_;
0421     mutable mutex_type mtx_;
0422   public:
0423     // construction/destruction
0424     /**
0425      * Default constructor.
0426      *
0427      * @Requires: T is DefaultConstructible
0428      */
0429     synchronized_value()
0430     //BOOST_NOEXCEPT_IF(is_nothrow_default_constructible<T>::value)
0431     : value_()
0432     {
0433     }
0434 
0435     /**
0436      * Constructor from copy constructible value.
0437      *
0438      * Requires: T is CopyConstructible
0439      */
0440     synchronized_value(T const& other)
0441     //BOOST_NOEXCEPT_IF(is_nothrow_copy_constructible<T>::value)
0442     : value_(other)
0443     {
0444     }
0445 
0446     /**
0447      * Move Constructor.
0448      *
0449      * Requires: T is CopyMovable
0450      */
0451     synchronized_value(BOOST_THREAD_RV_REF(T) other)
0452     //BOOST_NOEXCEPT_IF(is_nothrow_move_constructible<T>::value)
0453     : value_(boost::move(other))
0454     {
0455     }
0456 
0457     /**
0458      * Constructor from value type.
0459      *
0460      * Requires: T is DefaultConstructible and Assignable
0461      * Effects: Assigns the value on a scope protected by the mutex of the rhs. The mutex is not copied.
0462      */
0463     synchronized_value(synchronized_value const& rhs)
0464     {
0465       strict_lock<mutex_type> lk(rhs.mtx_);
0466       value_ = rhs.value_;
0467     }
0468 
0469     /**
0470      * Move Constructor from movable value type
0471      *
0472      */
0473     synchronized_value(BOOST_THREAD_RV_REF(synchronized_value) other)
0474     {
0475       strict_lock<mutex_type> lk(BOOST_THREAD_RV(other).mtx_);
0476       value_= boost::move(BOOST_THREAD_RV(other).value_);
0477     }
0478 
0479     // mutation
0480     /**
0481      * Assignment operator.
0482      *
0483      * Effects: Copies the underlying value on a scope protected by the two mutexes.
0484      * The mutex is not copied. The locks are acquired using lock, so deadlock is avoided.
0485      * For example, there is no problem if one thread assigns a = b and the other assigns b = a.
0486      *
0487      * Return: *this
0488      */
0489 
0490     synchronized_value& operator=(synchronized_value const& rhs)
0491     {
0492       if(&rhs != this)
0493       {
0494         // auto _ = make_unique_locks(mtx_, rhs.mtx_);
0495         unique_lock<mutex_type> lk1(mtx_, defer_lock);
0496         unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
0497         lock(lk1,lk2);
0498 
0499         value_ = rhs.value_;
0500       }
0501       return *this;
0502     }
0503     /**
0504      * Assignment operator from a T const&.
0505      * Effects: The operator copies the value on a scope protected by the mutex.
0506      * Return: *this
0507      */
0508     synchronized_value& operator=(value_type const& val)
0509     {
0510       {
0511         strict_lock<mutex_type> lk(mtx_);
0512         value_ = val;
0513       }
0514       return *this;
0515     }
0516 
0517     //observers
0518     /**
0519      * Explicit conversion to value type.
0520      *
0521      * Requires: T is CopyConstructible
0522      * Return: A copy of the protected value obtained on a scope protected by the mutex.
0523      *
0524      */
0525     T get() const
0526     {
0527       strict_lock<mutex_type> lk(mtx_);
0528       return value_;
0529     }
0530     /**
0531      * Explicit conversion to value type.
0532      *
0533      * Requires: T is CopyConstructible
0534      * Return: A copy of the protected value obtained on a scope protected by the mutex.
0535      *
0536      */
0537 #if ! defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
0538     explicit operator T() const
0539     {
0540       return get();
0541     }
0542 #endif
0543 
0544     /**
0545      * value type getter.
0546      *
0547      * Return: A constant reference to the protected value.
0548      *
0549      * Note: Not thread safe
0550      *
0551      */
0552     T const& value() const
0553     {
0554       return value_;
0555     }
0556     /**
0557      * mutex getter.
0558      *
0559      * Return: A constant reference to the protecting mutex.
0560      *
0561      * Note: Not thread safe
0562      *
0563      */
0564     mutex_type const& mutex() const
0565     {
0566       return mtx_;
0567     }
0568     /**
0569      * Swap
0570      *
0571      * Effects: Swaps the data. Again, locks are acquired using lock(). The mutexes are not swapped.
0572      * A swap method accepts a T& and swaps the data inside a critical section.
0573      * This is by far the preferred method of changing the guarded datum wholesale because it keeps the lock only
0574      * for a short time, thus lowering the pressure on the mutex.
0575      */
0576     void swap(synchronized_value & rhs)
0577     {
0578       if (this == &rhs) {
0579         return;
0580       }
0581       // auto _ = make_unique_locks(mtx_, rhs.mtx_);
0582       unique_lock<mutex_type> lk1(mtx_, defer_lock);
0583       unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
0584       lock(lk1,lk2);
0585       boost::core::invoke_swap(value_, rhs.value_);
0586     }
0587     /**
0588      * Swap with the underlying value type
0589      *
0590      * Effects: Swaps the data on a scope protected by the mutex.
0591      */
0592     void swap(value_type & rhs)
0593     {
0594       strict_lock<mutex_type> lk(mtx_);
0595       boost::core::invoke_swap(value_, rhs);
0596     }
0597 
0598     /**
0599      * Essentially calling a method obj->foo(x, y, z) calls the method foo(x, y, z) inside a critical section as
0600      * long-lived as the call itself.
0601      */
0602     strict_lock_ptr<T,Lockable> operator->()
0603     {
0604       return BOOST_THREAD_MAKE_RV_REF((strict_lock_ptr<T,Lockable>(value_, mtx_)));
0605     }
0606     /**
0607      * If the synchronized_value object involved is const-qualified, then you'll only be able to call const methods
0608      * through operator->. So, for example, vec->push_back("xyz") won't work if vec were const-qualified.
0609      * The locking mechanism capitalizes on the assumption that const methods don't modify their underlying data.
0610      */
0611     const_strict_lock_ptr<T,Lockable> operator->() const
0612     {
0613       return BOOST_THREAD_MAKE_RV_REF((const_strict_lock_ptr<T,Lockable>(value_, mtx_)));
0614     }
0615 
0616     /**
0617      * Call function on a locked block.
0618      *
0619      * @requires fct(value_) is well formed.
0620      *
0621      * Example
0622      *   void fun(synchronized_value<vector<int>> & v) {
0623      *     v ( [](vector<int>> & vec)
0624      *     {
0625      *       vec.push_back(42);
0626      *       assert(vec.back() == 42);
0627      *     } );
0628      *   }
0629      */
0630     template <typename F>
0631     inline
0632     typename boost::result_of<F(value_type&)>::type
0633     operator()(BOOST_THREAD_RV_REF(F) fct)
0634     {
0635       strict_lock<mutex_type> lk(mtx_);
0636       return fct(value_);
0637     }
0638     template <typename F>
0639     inline
0640     typename boost::result_of<F(value_type const&)>::type
0641     operator()(BOOST_THREAD_RV_REF(F) fct) const
0642     {
0643       strict_lock<mutex_type> lk(mtx_);
0644       return fct(value_);
0645     }
0646 
0647 
0648 #if defined  BOOST_NO_CXX11_RVALUE_REFERENCES
0649     template <typename F>
0650     inline
0651     typename boost::result_of<F(value_type&)>::type
0652     operator()(F const & fct)
0653     {
0654       strict_lock<mutex_type> lk(mtx_);
0655       return fct(value_);
0656     }
0657     template <typename F>
0658     inline
0659     typename boost::result_of<F(value_type const&)>::type
0660     operator()(F const & fct) const
0661     {
0662       strict_lock<mutex_type> lk(mtx_);
0663       return fct(value_);
0664     }
0665 
0666     template <typename R>
0667     inline
0668     R operator()(R(*fct)(value_type&))
0669     {
0670       strict_lock<mutex_type> lk(mtx_);
0671       return fct(value_);
0672     }
0673     template <typename R>
0674     inline
0675     R operator()(R(*fct)(value_type const&)) const
0676     {
0677       strict_lock<mutex_type> lk(mtx_);
0678       return fct(value_);
0679     }
0680 #endif
0681 
0682 
0683     /**
0684      * The synchronize() factory make easier to lock on a scope.
0685      * As discussed, operator-> can only lock over the duration of a call, so it is insufficient for complex operations.
0686      * With synchronize() you get to lock the object in a scoped and to directly access the object inside that scope.
0687      *
0688      * Example
0689      *   void fun(synchronized_value<vector<int>> & v) {
0690      *     auto&& vec=v.synchronize();
0691      *     vec.push_back(42);
0692      *     assert(vec.back() == 42);
0693      *   }
0694      */
0695     strict_lock_ptr<T,Lockable> synchronize()
0696     {
0697       return BOOST_THREAD_MAKE_RV_REF((strict_lock_ptr<T,Lockable>(value_, mtx_)));
0698     }
0699     const_strict_lock_ptr<T,Lockable> synchronize() const
0700     {
0701       return BOOST_THREAD_MAKE_RV_REF((const_strict_lock_ptr<T,Lockable>(value_, mtx_)));
0702     }
0703 
0704     unique_lock_ptr<T,Lockable> unique_synchronize()
0705     {
0706       return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_)));
0707     }
0708     const_unique_lock_ptr<T,Lockable> unique_synchronize() const
0709     {
0710       return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_)));
0711     }
0712     unique_lock_ptr<T,Lockable> unique_synchronize(defer_lock_t tag)
0713     {
0714       return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_, tag)));
0715     }
0716     const_unique_lock_ptr<T,Lockable> unique_synchronize(defer_lock_t tag) const
0717     {
0718       return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_, tag)));
0719     }
0720     unique_lock_ptr<T,Lockable> defer_synchronize() BOOST_NOEXCEPT
0721     {
0722       return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_, defer_lock)));
0723     }
0724     const_unique_lock_ptr<T,Lockable> defer_synchronize() const BOOST_NOEXCEPT
0725     {
0726       return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_, defer_lock)));
0727     }
0728     unique_lock_ptr<T,Lockable> try_to_synchronize() BOOST_NOEXCEPT
0729     {
0730       return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_, try_to_lock)));
0731     }
0732     const_unique_lock_ptr<T,Lockable> try_to_synchronize() const BOOST_NOEXCEPT
0733     {
0734       return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_, try_to_lock)));
0735     }
0736     unique_lock_ptr<T,Lockable> adopt_synchronize() BOOST_NOEXCEPT
0737     {
0738       return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_, adopt_lock)));
0739     }
0740     const_unique_lock_ptr<T,Lockable> adopt_synchronize() const BOOST_NOEXCEPT
0741     {
0742       return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_, adopt_lock)));
0743     }
0744 
0745 
0746 #if ! defined __IBMCPP__
0747     private:
0748 #endif
0749     class deref_value
0750     {
0751     private:
0752       friend class synchronized_value;
0753 
0754       boost::unique_lock<mutex_type> lk_;
0755       T& value_;
0756 
0757       explicit deref_value(synchronized_value& outer):
0758       lk_(outer.mtx_),value_(outer.value_)
0759       {}
0760 
0761     public:
0762       BOOST_THREAD_MOVABLE_ONLY(deref_value)
0763 
0764       deref_value(BOOST_THREAD_RV_REF(deref_value) other):
0765       lk_(boost::move(BOOST_THREAD_RV(other).lk_)),value_(BOOST_THREAD_RV(other).value_)
0766       {}
0767       operator T&()
0768       {
0769         return value_;
0770       }
0771 
0772       deref_value& operator=(T const& newVal)
0773       {
0774         value_=newVal;
0775         return *this;
0776       }
0777     };
0778     class const_deref_value
0779     {
0780     private:
0781       friend class synchronized_value;
0782 
0783       boost::unique_lock<mutex_type> lk_;
0784       const T& value_;
0785 
0786       explicit const_deref_value(synchronized_value const& outer):
0787       lk_(outer.mtx_), value_(outer.value_)
0788       {}
0789 
0790     public:
0791       BOOST_THREAD_MOVABLE_ONLY(const_deref_value)
0792 
0793       const_deref_value(BOOST_THREAD_RV_REF(const_deref_value) other):
0794       lk_(boost::move(BOOST_THREAD_RV(other).lk_)), value_(BOOST_THREAD_RV(other).value_)
0795       {}
0796 
0797       operator const T&()
0798       {
0799         return value_;
0800       }
0801     };
0802 
0803   public:
0804     deref_value operator*()
0805     {
0806       return BOOST_THREAD_MAKE_RV_REF(deref_value(*this));
0807     }
0808 
0809     const_deref_value operator*() const
0810     {
0811       return BOOST_THREAD_MAKE_RV_REF(const_deref_value(*this));
0812     }
0813 
0814     // io functions
0815     /**
0816      * @requires T is OutputStreamable
0817      * @effects saves the value type on the output stream @c os.
0818      */
0819     template <typename OStream>
0820     void save(OStream& os) const
0821     {
0822       strict_lock<mutex_type> lk(mtx_);
0823       os << value_;
0824     }
0825     /**
0826      * @requires T is InputStreamable
0827      * @effects loads the value type from the input stream @c is.
0828      */
0829     template <typename IStream>
0830     void load(IStream& is)
0831     {
0832       strict_lock<mutex_type> lk(mtx_);
0833       is >> value_;
0834     }
0835 
0836     // relational operators
0837     /**
0838      * @requires T is EqualityComparable
0839      *
0840      */
0841     bool operator==(synchronized_value const& rhs)  const
0842     {
0843       unique_lock<mutex_type> lk1(mtx_, defer_lock);
0844       unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
0845       lock(lk1,lk2);
0846 
0847       return value_ == rhs.value_;
0848     }
0849     /**
0850      * @requires T is LessThanComparable
0851      *
0852      */
0853     bool operator<(synchronized_value const& rhs) const
0854     {
0855       unique_lock<mutex_type> lk1(mtx_, defer_lock);
0856       unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
0857       lock(lk1,lk2);
0858 
0859       return value_ < rhs.value_;
0860     }
0861     /**
0862      * @requires T is GreaterThanComparable
0863      *
0864      */
0865     bool operator>(synchronized_value const& rhs) const
0866     {
0867       unique_lock<mutex_type> lk1(mtx_, defer_lock);
0868       unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
0869       lock(lk1,lk2);
0870 
0871       return value_ > rhs.value_;
0872     }
0873     bool operator<=(synchronized_value const& rhs) const
0874     {
0875       unique_lock<mutex_type> lk1(mtx_, defer_lock);
0876       unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
0877       lock(lk1,lk2);
0878 
0879       return value_ <= rhs.value_;
0880     }
0881     bool operator>=(synchronized_value const& rhs) const
0882     {
0883       unique_lock<mutex_type> lk1(mtx_, defer_lock);
0884       unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
0885       lock(lk1,lk2);
0886 
0887       return value_ >= rhs.value_;
0888     }
0889     bool operator==(value_type const& rhs) const
0890     {
0891       unique_lock<mutex_type> lk1(mtx_);
0892 
0893       return value_ == rhs;
0894     }
0895     bool operator!=(value_type const& rhs) const
0896     {
0897       unique_lock<mutex_type> lk1(mtx_);
0898 
0899       return value_ != rhs;
0900     }
0901     bool operator<(value_type const& rhs) const
0902     {
0903       unique_lock<mutex_type> lk1(mtx_);
0904 
0905       return value_ < rhs;
0906     }
0907     bool operator<=(value_type const& rhs) const
0908     {
0909       unique_lock<mutex_type> lk1(mtx_);
0910 
0911       return value_ <= rhs;
0912     }
0913     bool operator>(value_type const& rhs) const
0914     {
0915       unique_lock<mutex_type> lk1(mtx_);
0916 
0917       return value_ > rhs;
0918     }
0919     bool operator>=(value_type const& rhs) const
0920     {
0921       unique_lock<mutex_type> lk1(mtx_);
0922 
0923       return value_ >= rhs;
0924     }
0925 
0926   };
0927 
0928   // Specialized algorithms
0929   /**
0930    *
0931    */
0932   template <typename T, typename L>
0933   inline void swap(synchronized_value<T,L> & lhs, synchronized_value<T,L> & rhs)
0934   {
0935     lhs.swap(rhs);
0936   }
0937   template <typename T, typename L>
0938   inline void swap(synchronized_value<T,L> & lhs, T & rhs)
0939   {
0940     lhs.swap(rhs);
0941   }
0942   template <typename T, typename L>
0943   inline void swap(T & lhs, synchronized_value<T,L> & rhs)
0944   {
0945     rhs.swap(lhs);
0946   }
0947 
0948   //Hash support
0949 
0950 //  template <class T> struct hash;
0951 //  template <typename T, typename L>
0952 //  struct hash<synchronized_value<T,L> >;
0953 
0954   // Comparison with T
0955   template <typename T, typename L>
0956   bool operator!=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
0957   {
0958     return ! (lhs==rhs);
0959   }
0960 
0961   template <typename T, typename L>
0962   bool operator==(T const& lhs, synchronized_value<T,L> const&rhs)
0963   {
0964     return rhs==lhs;
0965   }
0966   template <typename T, typename L>
0967   bool operator!=(T const& lhs, synchronized_value<T,L> const&rhs)
0968   {
0969     return rhs!=lhs;
0970   }
0971   template <typename T, typename L>
0972   bool operator<(T const& lhs, synchronized_value<T,L> const&rhs)
0973   {
0974     return rhs>lhs;
0975   }
0976   template <typename T, typename L>
0977   bool operator<=(T const& lhs, synchronized_value<T,L> const&rhs)
0978   {
0979     return rhs>=lhs;
0980   }
0981   template <typename T, typename L>
0982   bool operator>(T const& lhs, synchronized_value<T,L> const&rhs)
0983   {
0984     return rhs<lhs;
0985   }
0986   template <typename T, typename L>
0987   bool operator>=(T const& lhs, synchronized_value<T,L> const&rhs)
0988   {
0989     return rhs<=lhs;
0990   }
0991 
0992   /**
0993    *
0994    */
0995   template <typename OStream, typename T, typename L>
0996   inline OStream& operator<<(OStream& os, synchronized_value<T,L> const& rhs)
0997   {
0998     rhs.save(os);
0999     return os;
1000   }
1001   template <typename IStream, typename T, typename L>
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>
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   >
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   >
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