Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:38:33

0001 //////////////////////////////////////////////////////////////////////////////
0002 //
0003 // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
0004 // Software License, Version 1.0. (See accompanying file
0005 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // See http://www.boost.org/libs/interprocess for documentation.
0008 //
0009 //////////////////////////////////////////////////////////////////////////////
0010 //
0011 // This interface is inspired by Howard Hinnant's lock proposal.
0012 // http://home.twcny.rr.com/hinnant/cpp_extensions/threads_move.html
0013 //
0014 //////////////////////////////////////////////////////////////////////////////
0015 
0016 #ifndef BOOST_INTERPROCESS_SHARABLE_LOCK_HPP
0017 #define BOOST_INTERPROCESS_SHARABLE_LOCK_HPP
0018 
0019 #ifndef BOOST_CONFIG_HPP
0020 #  include <boost/config.hpp>
0021 #endif
0022 #
0023 #if defined(BOOST_HAS_PRAGMA_ONCE)
0024 #  pragma once
0025 #endif
0026 
0027 #include <boost/interprocess/detail/config_begin.hpp>
0028 #include <boost/interprocess/detail/workaround.hpp>
0029 #include <boost/interprocess/interprocess_fwd.hpp>
0030 #include <boost/interprocess/sync/lock_options.hpp>
0031 #include <boost/interprocess/exceptions.hpp>
0032 #include <boost/interprocess/detail/mpl.hpp>
0033 #include <boost/interprocess/detail/type_traits.hpp>
0034 #include <boost/interprocess/detail/simple_swap.hpp>
0035 #include <boost/move/utility_core.hpp>
0036 
0037 //!\file
0038 //!Describes the upgradable_lock class that serves to acquire the upgradable
0039 //!lock of a mutex.
0040 
0041 namespace boost {
0042 namespace interprocess {
0043 
0044 
0045 //!sharable_lock is meant to carry out the tasks for sharable-locking
0046 //!(such as read-locking), unlocking, try-sharable-locking and timed-sharable-locking
0047 //!(recursive or not) for the Mutex. The Mutex need not supply all of this
0048 //!functionality. If the client of sharable_lock<Mutex> does not use functionality which
0049 //!the Mutex does not supply, no harm is done. Mutex ownership can be shared among
0050 //!sharable_locks, and a single upgradable_lock. sharable_lock does not support
0051 //!copy semantics. But sharable_lock supports ownership transfer from an sharable_lock,
0052 //!upgradable_lock and scoped_lock via transfer_lock syntax.*/
0053 template <class SharableMutex>
0054 class sharable_lock
0055 {
0056    public:
0057    typedef SharableMutex mutex_type;
0058    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
0059    private:
0060    typedef sharable_lock<SharableMutex> this_type;
0061    explicit sharable_lock(scoped_lock<mutex_type>&);
0062    typedef bool this_type::*unspecified_bool_type;
0063    BOOST_MOVABLE_BUT_NOT_COPYABLE(sharable_lock)
0064    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
0065    public:
0066 
0067    //!Effects: Default constructs a sharable_lock.
0068    //!Postconditions: owns() == false and mutex() == 0.
0069    sharable_lock() BOOST_NOEXCEPT
0070       : mp_mutex(0), m_locked(false)
0071    {}
0072 
0073    //!Effects: m.lock_sharable().
0074    //!Postconditions: owns() == true and mutex() == &m.
0075    //!Notes: The constructor will take sharable-ownership of the mutex. If
0076    //!   another thread already owns the mutex with exclusive ownership
0077    //!   (scoped_lock), this thread will block until the mutex is released.
0078    //!   If another thread owns the mutex with sharable or upgradable ownership,
0079    //!   then no blocking will occur. Whether or not this constructor handles
0080    //!   recursive locking depends upon the mutex.
0081    explicit sharable_lock(mutex_type& m)
0082       : mp_mutex(&m), m_locked(false)
0083    {  mp_mutex->lock_sharable();   m_locked = true;  }
0084 
0085    //!Postconditions: owns() == false, and mutex() == &m.
0086    //!Notes: The constructor will not take ownership of the mutex. There is no effect
0087    //!   required on the referenced mutex.
0088    sharable_lock(mutex_type& m, defer_lock_type)
0089       : mp_mutex(&m), m_locked(false)
0090    {}
0091 
0092    //!Postconditions: owns() == true, and mutex() == &m.
0093    //!Notes: The constructor will suppose that the mutex is already sharable
0094    //!   locked. There is no effect required on the referenced mutex.
0095    sharable_lock(mutex_type& m, accept_ownership_type)
0096       : mp_mutex(&m), m_locked(true)
0097    {}
0098 
0099    //!Effects: m.try_lock_sharable()
0100    //!Postconditions: mutex() == &m. owns() == the return value of the
0101    //!   m.try_lock_sharable() executed within the constructor.
0102    //!Notes: The constructor will take sharable-ownership of the mutex if it
0103    //!   can do so without waiting. Whether or not this constructor handles
0104    //!   recursive locking depends upon the mutex. If the mutex_type does not
0105    //!   support try_lock_sharable, this constructor will fail at compile
0106    //!   time if instantiated, but otherwise have no effect.
0107    sharable_lock(mutex_type& m, try_to_lock_type)
0108       : mp_mutex(&m), m_locked(false)
0109    {  m_locked = mp_mutex->try_lock_sharable();   }
0110 
0111    //!Effects: m.timed_lock_sharable(abs_time)
0112    //!Postconditions: mutex() == &m. owns() == the return value of the
0113    //!   m.timed_lock_sharable() executed within the constructor.
0114    //!Notes: The constructor will take sharable-ownership of the mutex if it
0115    //!   can do so within the time specified. Whether or not this constructor
0116    //!   handles recursive locking depends upon the mutex. If the mutex_type
0117    //!   does not support timed_lock_sharable, this constructor will fail at
0118    //!   compile time if instantiated, but otherwise have no effect.
0119    template<class TimePoint>
0120    sharable_lock(mutex_type& m, const TimePoint& abs_time)
0121       : mp_mutex(&m), m_locked(false)
0122    {  m_locked = mp_mutex->timed_lock_sharable(abs_time);  }
0123 
0124    //!Postconditions: mutex() == upgr.mutex(). owns() == the value of upgr.owns()
0125    //!   before the construction. upgr.owns() == false after the construction.
0126    //!Notes: If the upgr sharable_lock owns the mutex, ownership is moved to this
0127    //!   sharable_lock with no blocking. If the upgr sharable_lock does not own the mutex, then
0128    //!   neither will this sharable_lock. Only a moved sharable_lock's will match this
0129    //!   signature. An non-moved sharable_lock can be moved with the expression:
0130    //!   "boost::move(lock);". This constructor does not alter the state of the mutex,
0131    //!   only potentially who owns it.
0132    sharable_lock(BOOST_RV_REF(sharable_lock<mutex_type>) upgr) BOOST_NOEXCEPT
0133       : mp_mutex(0), m_locked(upgr.owns())
0134    {  mp_mutex = upgr.release(); }
0135 
0136    //!Effects: If upgr.owns() then calls unlock_upgradable_and_lock_sharable() on the
0137    //!   referenced mutex.
0138    //!Postconditions: mutex() == the value upgr.mutex() had before the construction.
0139    //!   upgr.mutex() == 0 owns() == the value of upgr.owns() before construction.
0140    //!   upgr.owns() == false after the construction.
0141    //!Notes: If upgr is locked, this constructor will lock this sharable_lock while
0142    //!   unlocking upgr. Only a moved sharable_lock's will match this
0143    //!   signature. An non-moved upgradable_lock can be moved with the expression:
0144    //!   "boost::move(lock);".*/
0145    template<class T>
0146    sharable_lock(BOOST_RV_REF(upgradable_lock<T>) upgr
0147       , typename ipcdetail::enable_if< ipcdetail::is_same<T, SharableMutex> >::type * = 0)
0148       : mp_mutex(0), m_locked(false)
0149    {
0150       upgradable_lock<mutex_type> &u_lock = upgr;
0151       if(u_lock.owns()){
0152          u_lock.mutex()->unlock_upgradable_and_lock_sharable();
0153          m_locked = true;
0154       }
0155       mp_mutex = u_lock.release();
0156    }
0157 
0158    //!Effects: If scop.owns() then calls unlock_and_lock_sharable() on the
0159    //!   referenced mutex.
0160    //!Postconditions: mutex() == the value scop.mutex() had before the construction.
0161    //!   scop.mutex() == 0 owns() == scop.owns() before the constructor. After the
0162    //!   construction, scop.owns() == false.
0163    //!Notes: If scop is locked, this constructor will transfer the exclusive ownership
0164    //!   to a sharable-ownership of this sharable_lock.
0165    //!   Only a moved scoped_lock's will match this
0166    //!   signature. An non-moved scoped_lock can be moved with the expression:
0167    //!   "boost::move(lock);".
0168    template<class T>
0169    sharable_lock(BOOST_RV_REF(scoped_lock<T>) scop
0170                , typename ipcdetail::enable_if< ipcdetail::is_same<T, SharableMutex> >::type * = 0)
0171       : mp_mutex(0), m_locked(false)
0172    {
0173       scoped_lock<mutex_type> &e_lock = scop;
0174       if(e_lock.owns()){
0175          e_lock.mutex()->unlock_and_lock_sharable();
0176          m_locked = true;
0177       }
0178       mp_mutex = e_lock.release();
0179    }
0180 
0181    //!Effects: if (owns()) mp_mutex->unlock_sharable().
0182    //!Notes: The destructor behavior ensures that the mutex lock is not leaked.
0183    ~sharable_lock()
0184    {
0185       BOOST_TRY{
0186          if(m_locked && mp_mutex)   mp_mutex->unlock_sharable();
0187       }
0188       BOOST_CATCH(...){} BOOST_CATCH_END
0189    }
0190 
0191    //!Effects: If owns() before the call, then unlock_sharable() is called on mutex().
0192    //!   *this gets the state of upgr and upgr gets set to a default constructed state.
0193    //!Notes: With a recursive mutex it is possible that both this and upgr own the mutex
0194    //!   before the assignment. In this case, this will own the mutex after the assignment
0195    //!   (and upgr will not), but the mutex's lock count will be decremented by one.
0196    sharable_lock &operator=(BOOST_RV_REF(sharable_lock<mutex_type>) upgr)
0197    {
0198       if(this->owns())
0199          this->unlock();
0200       m_locked = upgr.owns();
0201       mp_mutex = upgr.release();
0202       return *this;
0203    }
0204 
0205    //!Effects: If mutex() == 0 or already locked, throws a lock_exception()
0206    //!   exception. Calls lock_sharable() on the referenced mutex.
0207    //!Postconditions: owns() == true.
0208    //!Notes: The sharable_lock changes from a state of not owning the
0209    //!   mutex, to owning the mutex, blocking if necessary.
0210    void lock()
0211    {
0212       if(!mp_mutex || m_locked)
0213          throw lock_exception();
0214       mp_mutex->lock_sharable();
0215       m_locked = true;
0216    }
0217 
0218    //!Effects: If mutex() == 0 or already locked, throws a lock_exception()
0219    //!   exception. Calls try_lock_sharable() on the referenced mutex.
0220    //!Postconditions: owns() == the value returned from
0221    //!   mutex()->try_lock_sharable().
0222    //!Notes: The sharable_lock changes from a state of not owning the mutex,
0223    //!   to owning the mutex, but only if blocking was not required. If the
0224    //!   mutex_type does not support try_lock_sharable(), this function will
0225    //!   fail at compile time if instantiated, but otherwise have no effect.
0226    bool try_lock()
0227    {
0228       if(!mp_mutex || m_locked)
0229          throw lock_exception();
0230       m_locked = mp_mutex->try_lock_sharable();
0231       return m_locked;
0232    }
0233 
0234    //!Effects: If mutex() == 0 or already locked, throws a lock_exception()
0235    //!   exception. Calls timed_lock_sharable(abs_time) on the referenced mutex.
0236    //!Postconditions: owns() == the value returned from
0237    //!   mutex()->timed_lock_sharable(elps_time).
0238    //!Notes: The sharable_lock changes from a state of not owning the mutex,
0239    //!   to owning the mutex, but only if it can obtain ownership within the
0240    //!   specified time interval. If the mutex_type does not support
0241    //!   timed_lock_sharable(), this function will fail at compile time if
0242    //!   instantiated, but otherwise have no effect.
0243    template<class TimePoint>
0244    bool timed_lock(const TimePoint& abs_time)
0245    {
0246       if(!mp_mutex || m_locked)
0247          throw lock_exception();
0248       m_locked = mp_mutex->timed_lock_sharable(abs_time);
0249       return m_locked;
0250    }
0251 
0252    //!Effects: If mutex() == 0 or already locked, throws a lock_exception()
0253    //!   exception. Calls try_lock_shared_until(abs_time) on the referenced mutex.
0254    //!Postconditions: owns() == the value returned from
0255    //!   mutex()->timed_lock_sharable(elps_time).
0256    //!Notes: The sharable_lock changes from a state of not owning the mutex,
0257    //!   to owning the mutex, but only if it can obtain ownership within the
0258    //!   specified time interval. If the mutex_type does not support
0259    //!   timed_lock_sharable(), this function will fail at compile time if
0260    //!   instantiated, but otherwise have no effect.
0261    //!
0262    //!Note: Similar to timed_lock, but with a std-like interface
0263    template<class TimePoint>
0264    bool try_lock_until(const TimePoint& abs_time)
0265    {
0266       if(!mp_mutex || m_locked)
0267          throw lock_exception();
0268       m_locked = mp_mutex->try_lock_shared_until(abs_time);
0269       return m_locked;
0270    }
0271 
0272    //!Effects: If mutex() == 0 or already locked, throws a lock_exception()
0273    //!   exception. Calls try_lock_shared_until(abs_time) on the referenced mutex.
0274    //!Postconditions: owns() == the value returned from
0275    //!   mutex()->timed_lock_sharable(elps_time).
0276    //!Notes: The sharable_lock changes from a state of not owning the mutex,
0277    //!   to owning the mutex, but only if it can obtain ownership within the
0278    //!   specified time interval. If the mutex_type does not support
0279    //!   timed_lock_sharable(), this function will fail at compile time if
0280    //!   instantiated, but otherwise have no effect.
0281    //!
0282    //!Note: Similar to timed_lock, but with a std-like interface
0283    template<class Duration>
0284    bool try_lock_for(const Duration& dur)
0285    {
0286       if(!mp_mutex || m_locked)
0287          throw lock_exception();
0288       m_locked = mp_mutex->try_lock_shared_for(dur);
0289       return m_locked;
0290    }
0291 
0292    //!Effects: If mutex() == 0 or not locked, throws a lock_exception() exception.
0293    //!   Calls unlock_sharable() on the referenced mutex.
0294    //!Postconditions: owns() == false.
0295    //!Notes: The sharable_lock changes from a state of owning the mutex, to
0296    //!   not owning the mutex.
0297    void unlock()
0298    {
0299       if(!mp_mutex || !m_locked)
0300          throw lock_exception();
0301       mp_mutex->unlock_sharable();
0302       m_locked = false;
0303    }
0304 
0305    //!Effects: Returns true if this scoped_lock has
0306    //!acquired the referenced mutex.
0307    bool owns() const BOOST_NOEXCEPT
0308    {  return m_locked && mp_mutex;  }
0309 
0310    //!Conversion to bool.
0311    //!Returns owns().
0312    operator unspecified_bool_type() const BOOST_NOEXCEPT
0313    {  return m_locked? &this_type::m_locked : 0;   }
0314 
0315    //!Effects: Returns a pointer to the referenced mutex, or 0 if
0316    //!there is no mutex to reference.
0317    mutex_type* mutex() const BOOST_NOEXCEPT
0318    {  return  mp_mutex;  }
0319 
0320    //!Effects: Returns a pointer to the referenced mutex, or 0 if there is no
0321    //!   mutex to reference.
0322    //!Postconditions: mutex() == 0 and owns() == false.
0323    mutex_type* release() BOOST_NOEXCEPT
0324    {
0325       mutex_type *mut = mp_mutex;
0326       mp_mutex = 0;
0327       m_locked = false;
0328       return mut;
0329    }
0330 
0331    //!Effects: Swaps state with moved lock.
0332    //!Throws: Nothing.
0333    void swap(sharable_lock<mutex_type> &other) BOOST_NOEXCEPT
0334    {
0335       (simple_swap)(mp_mutex, other.mp_mutex);
0336       (simple_swap)(m_locked, other.m_locked);
0337    }
0338 
0339    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
0340    private:
0341    mutex_type *mp_mutex;
0342    bool        m_locked;
0343    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
0344 };
0345 
0346 } // namespace interprocess
0347 } // namespace boost
0348 
0349 #include <boost/interprocess/detail/config_end.hpp>
0350 
0351 #endif // BOOST_INTERPROCESS_SHARABLE_LOCK_HPP