Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-07 08:07:51

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_SCOPED_LOCK_HPP
0017 #define BOOST_INTERPROCESS_SCOPED_LOCK_HPP
0018 
0019 #ifndef BOOST_CONFIG_HPP
0020 #  include <boost/config.hpp>
0021 #endif
0022 0023 ">#
0024 #if defined(BOOST_HAS_PRAGMA_ONCE)
0025 #  pragma once
0026 #endif
0027 
0028 #include <boost/interprocess/detail/config_begin.hpp>
0029 #include <boost/interprocess/detail/workaround.hpp>
0030 #include <boost/interprocess/interprocess_fwd.hpp>
0031 #include <boost/interprocess/sync/lock_options.hpp>
0032 #include <boost/interprocess/exceptions.hpp>
0033 #include <boost/interprocess/detail/mpl.hpp>
0034 #include <boost/interprocess/detail/type_traits.hpp>
0035 #include <boost/move/utility_core.hpp>
0036 #include <boost/interprocess/detail/simple_swap.hpp>
0037 
0038 //!\file
0039 //!Describes the scoped_lock class.
0040 
0041 namespace boost {
0042 namespace interprocess {
0043 
0044 
0045 //!scoped_lock is meant to carry out the tasks for locking, unlocking, try-locking
0046 //!and timed-locking (recursive or not) for the Mutex. The Mutex need not supply all
0047 //!of this functionality. If the client of scoped_lock<Mutex> does not use
0048 //!functionality which the Mutex does not supply, no harm is done. Mutex ownership
0049 //!transfer is supported through the syntax of move semantics. Ownership transfer
0050 //!is allowed both by construction and assignment. The scoped_lock does not support
0051 //!copy semantics. A compile time error results if copy construction or copy
0052 //!assignment is attempted. Mutex ownership can also be moved from an
0053 //!upgradable_lock and sharable_lock via constructor. In this role, scoped_lock
0054 //!shares the same functionality as a write_lock.
0055 template <class Mutex>
0056 class scoped_lock
0057 {
0058    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
0059    private:
0060    typedef scoped_lock<Mutex> this_type;
0061    BOOST_MOVABLE_BUT_NOT_COPYABLE(scoped_lock)
0062    typedef bool this_type::*unspecified_bool_type;
0063    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
0064    public:
0065 
0066    typedef Mutex mutex_type;
0067 
0068    //!Effects: Default constructs a scoped_lock.
0069    //!Postconditions: owns() == false and mutex() == 0.
0070    scoped_lock() BOOST_NOEXCEPT
0071       : mp_mutex(0), m_locked(false)
0072    {}
0073 
0074    //!Effects: m.lock().
0075    //!Postconditions: owns() == true and mutex() == &m.
0076    //!Notes: The constructor will take ownership of the mutex. If another thread
0077    //!   already owns the mutex, this thread will block until the mutex is released.
0078    //!   Whether or not this constructor handles recursive locking depends upon the mutex.
0079    explicit scoped_lock(mutex_type& m)
0080       : mp_mutex(&m), m_locked(false)
0081    {  mp_mutex->lock();   m_locked = true;  }
0082 
0083    //!Postconditions: owns() == false, and mutex() == &m.
0084    //!Notes: The constructor will not take ownership of the mutex. There is no effect
0085    //!   required on the referenced mutex.
0086    scoped_lock(mutex_type& m, defer_lock_type)
0087       : mp_mutex(&m), m_locked(false)
0088    {}
0089 
0090    //!Postconditions: owns() == true, and mutex() == &m.
0091    //!Notes: The constructor will suppose that the mutex is already locked. There
0092    //!   is no effect required on the referenced mutex.
0093    scoped_lock(mutex_type& m, accept_ownership_type)
0094       : mp_mutex(&m), m_locked(true)
0095    {}
0096 
0097    //!Effects: m.try_lock().
0098    //!Postconditions: mutex() == &m. owns() == the return value of the
0099    //!   m.try_lock() executed within the constructor.
0100    //!Notes: The constructor will take ownership of the mutex if it can do
0101    //!   so without waiting. Whether or not this constructor handles recursive
0102    //!   locking depends upon the mutex. If the mutex_type does not support try_lock,
0103    //!   this constructor will fail at compile time if instantiated, but otherwise
0104    //!   have no effect.
0105    scoped_lock(mutex_type& m, try_to_lock_type)
0106       : mp_mutex(&m), m_locked(mp_mutex->try_lock())
0107    {}
0108 
0109    //!Effects: m.timed_lock(abs_time).
0110    //!Postconditions: mutex() == &m. owns() == the return value of the
0111    //!   m.timed_lock(abs_time) executed within the constructor.
0112    //!Notes: The constructor will take ownership of the mutex if it can do
0113    //!   it until abs_time is reached. Whether or not this constructor
0114    //!   handles recursive locking depends upon the mutex. If the mutex_type
0115    //!   does not support try_lock, this constructor will fail at compile
0116    //!   time if instantiated, but otherwise have no effect.
0117    template<class TimePoint>
0118    scoped_lock(mutex_type& m, const TimePoint& abs_time)
0119       : mp_mutex(&m), m_locked(mp_mutex->timed_lock(abs_time))
0120    {}
0121 
0122    //!Postconditions: mutex() == the value scop.mutex() had before the
0123    //!   constructor executes. s1.mutex() == 0. owns() == the value of
0124    //!   scop.owns() before the constructor executes. scop.owns().
0125    //!Notes: If the scop scoped_lock owns the mutex, ownership is moved
0126    //!   to thisscoped_lock with no blocking. If the scop scoped_lock does not
0127    //!   own the mutex, then neither will this scoped_lock. Only a moved
0128    //!   scoped_lock's will match this signature. An non-moved scoped_lock
0129    //!   can be moved with the expression: "boost::move(lock);". This
0130    //!   constructor does not alter the state of the mutex, only potentially
0131    //!   who owns it.
0132    scoped_lock(BOOST_RV_REF(scoped_lock) scop) BOOST_NOEXCEPT
0133       : mp_mutex(0), m_locked(scop.owns())
0134    {  mp_mutex = scop.release(); }
0135 
0136    //!Effects: If upgr.owns() then calls unlock_upgradable_and_lock() on the
0137    //!   referenced mutex. upgr.release() is called.
0138    //!Postconditions: mutex() == the value upgr.mutex() had before the construction.
0139    //!   upgr.mutex() == 0. owns() == upgr.owns() before the construction.
0140    //!   upgr.owns() == false after the construction.
0141    //!Notes: If upgr is locked, this constructor will lock this scoped_lock while
0142    //!   unlocking upgr. If upgr is unlocked, then this scoped_lock will be
0143    //!   unlocked as well. Only a moved upgradable_lock's will match this
0144    //!   signature. An non-moved upgradable_lock can be moved with
0145    //!   the expression: "boost::move(lock);" This constructor may block if
0146    //!   other threads hold a sharable_lock on this mutex (sharable_lock's can
0147    //!   share ownership with an upgradable_lock).
0148    template<class T>
0149    explicit scoped_lock(BOOST_RV_REF(upgradable_lock<T>) upgr
0150       , typename ipcdetail::enable_if< ipcdetail::is_same<T, Mutex> >::type * = 0)
0151       : mp_mutex(0), m_locked(false)
0152    {
0153       upgradable_lock<mutex_type> &u_lock = upgr;
0154       if(u_lock.owns()){
0155          u_lock.mutex()->unlock_upgradable_and_lock();
0156          m_locked = true;
0157       }
0158       mp_mutex = u_lock.release();
0159    }
0160 
0161    //!Effects: If upgr.owns() then calls try_unlock_upgradable_and_lock() on the
0162    //!referenced mutex:
0163    //!   a)if try_unlock_upgradable_and_lock() returns true then mutex() obtains
0164    //!      the value from upgr.release() and owns() is set to true.
0165    //!   b)if try_unlock_upgradable_and_lock() returns false then upgr is
0166    //!      unaffected and this scoped_lock construction as the same effects as
0167    //!      a default construction.
0168    //!   c)Else upgr.owns() is false. mutex() obtains the value from upgr.release()
0169    //!      and owns() is set to false
0170    //!Notes: This construction will not block. It will try to obtain mutex
0171    //!   ownership from upgr immediately, while changing the lock type from a
0172    //!   "read lock" to a "write lock". If the "read lock" isn't held in the
0173    //!   first place, the mutex merely changes type to an unlocked "write lock".
0174    //!   If the "read lock" is held, then mutex transfer occurs only if it can
0175    //!   do so in a non-blocking manner.
0176    template<class T>
0177    scoped_lock(BOOST_RV_REF(upgradable_lock<T>) upgr, try_to_lock_type
0178          , typename ipcdetail::enable_if< ipcdetail::is_same<T, Mutex> >::type * = 0)
0179       : mp_mutex(0), m_locked(false)
0180    {
0181       upgradable_lock<mutex_type> &u_lock = upgr;
0182       if(u_lock.owns()){
0183          if((m_locked = u_lock.mutex()->try_unlock_upgradable_and_lock()) == true){
0184             mp_mutex = u_lock.release();
0185          }
0186       }
0187       else{
0188          u_lock.release();
0189       }
0190    }
0191 
0192    //!Effects: If upgr.owns() then calls timed_unlock_upgradable_and_lock(abs_time)
0193    //!   on the referenced mutex:
0194    //!   a)if timed_unlock_upgradable_and_lock(abs_time) returns true then mutex()
0195    //!      obtains the value from upgr.release() and owns() is set to true.
0196    //!   b)if timed_unlock_upgradable_and_lock(abs_time) returns false then upgr
0197    //!      is unaffected and this scoped_lock construction as the same effects
0198    //!      as a default construction.
0199    //!   c)Else upgr.owns() is false. mutex() obtains the value from upgr.release()
0200    //!      and owns() is set to false
0201    //!Notes: This construction will not block. It will try to obtain mutex ownership
0202    //!   from upgr immediately, while changing the lock type from a "read lock" to a
0203    //!   "write lock". If the "read lock" isn't held in the first place, the mutex
0204    //!   merely changes type to an unlocked "write lock". If the "read lock" is held,
0205    //!   then mutex transfer occurs only if it can do so in a non-blocking manner.
0206    template<class T, class TimePoint>
0207    scoped_lock(BOOST_RV_REF(upgradable_lock<T>) upgr, const TimePoint &abs_time
0208                , typename ipcdetail::enable_if< ipcdetail::is_same<T, Mutex> >::type * = 0)
0209       : mp_mutex(0), m_locked(false)
0210    {
0211       upgradable_lock<mutex_type> &u_lock = upgr;
0212       if(u_lock.owns()){
0213          if((m_locked = u_lock.mutex()->timed_unlock_upgradable_and_lock(abs_time)) == true){
0214             mp_mutex = u_lock.release();
0215          }
0216       }
0217       else{
0218          u_lock.release();
0219       }
0220    }
0221 
0222    //!Effects: If shar.owns() then calls try_unlock_sharable_and_lock() on the
0223    //!referenced mutex.
0224    //!   a)if try_unlock_sharable_and_lock() returns true then mutex() obtains
0225    //!      the value from shar.release() and owns() is set to true.
0226    //!   b)if try_unlock_sharable_and_lock() returns false then shar is
0227    //!      unaffected and this scoped_lock construction has the same
0228    //!      effects as a default construction.
0229    //!   c)Else shar.owns() is false. mutex() obtains the value from
0230    //!      shar.release() and owns() is set to false
0231    //!Notes: This construction will not block. It will try to obtain mutex
0232    //!   ownership from shar immediately, while changing the lock type from a
0233    //!   "read lock" to a "write lock". If the "read lock" isn't held in the
0234    //!   first place, the mutex merely changes type to an unlocked "write lock".
0235    //!   If the "read lock" is held, then mutex transfer occurs only if it can
0236    //!   do so in a non-blocking manner.
0237    template<class T>
0238    scoped_lock(BOOST_RV_REF(sharable_lock<T>) shar, try_to_lock_type
0239       , typename ipcdetail::enable_if< ipcdetail::is_same<T, Mutex> >::type * = 0)
0240       : mp_mutex(0), m_locked(false)
0241    {
0242       sharable_lock<mutex_type> &s_lock = shar;
0243       if(s_lock.owns()){
0244          if((m_locked = s_lock.mutex()->try_unlock_sharable_and_lock()) == true){
0245             mp_mutex = s_lock.release();
0246          }
0247       }
0248       else{
0249          s_lock.release();
0250       }
0251    }
0252 
0253    //!Effects: if (owns()) mp_mutex->unlock().
0254    //!Notes: The destructor behavior ensures that the mutex lock is not leaked.*/
0255    ~scoped_lock()
0256    {
0257       BOOST_INTERPROCESS_TRY{  if(m_locked && mp_mutex)   mp_mutex->unlock();  }
0258       BOOST_INTERPROCESS_CATCH(...){} BOOST_INTERPROCESS_CATCH_END
0259    }
0260 
0261    //!Effects: If owns() before the call, then unlock() is called on mutex().
0262    //!   *this gets the state of scop and scop gets set to a default constructed state.
0263    //!Notes: With a recursive mutex it is possible that both this and scop own
0264    //!   the same mutex before the assignment. In this case, this will own the
0265    //!   mutex after the assignment (and scop will not), but the mutex's lock
0266    //!   count will be decremented by one.
0267    scoped_lock &operator=(BOOST_RV_REF(scoped_lock) scop)
0268    {
0269       if(this->owns())
0270          this->unlock();
0271       m_locked = scop.owns();
0272       mp_mutex = scop.release();
0273       return *this;
0274    }
0275 
0276    //!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
0277    //!   exception. Calls lock() on the referenced mutex.
0278    //!Postconditions: owns() == true.
0279    //!Notes: The scoped_lock changes from a state of not owning the mutex, to
0280    //!   owning the mutex, blocking if necessary.
0281    void lock()
0282    {
0283       if(!mp_mutex || m_locked)
0284          throw lock_exception();
0285       mp_mutex->lock();
0286       m_locked = true;
0287    }
0288 
0289    //!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
0290    //!   exception. Calls try_lock() on the referenced mutex.
0291    //!Postconditions: owns() == the value returned from mutex()->try_lock().
0292    //!Notes: The scoped_lock changes from a state of not owning the mutex, to
0293    //!   owning the mutex, but only if blocking was not required. If the
0294    //!   mutex_type does not support try_lock(), this function will fail at
0295    //!   compile time if instantiated, but otherwise have no effect.*/
0296    bool try_lock()
0297    {
0298       if(!mp_mutex || m_locked)
0299          throw lock_exception();
0300       m_locked = mp_mutex->try_lock();
0301       return m_locked;
0302    }
0303 
0304    //!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
0305    //!   exception. Calls timed_lock(abs_time) on the referenced mutex.
0306    //!Postconditions: owns() == the value returned from mutex()-> timed_lock(abs_time).
0307    //!Notes: The scoped_lock changes from a state of not owning the mutex, to
0308    //!   owning the mutex, but only if it can obtain ownership by the specified
0309    //!   time. If the mutex_type does not support timed_lock (), this function
0310    //!   will fail at compile time if instantiated, but otherwise have no effect.*/
0311    template<class TimePoint>
0312    bool timed_lock(const TimePoint& abs_time)
0313    {
0314       if(!mp_mutex || m_locked)
0315          throw lock_exception();
0316       m_locked = mp_mutex->timed_lock(abs_time);
0317       return m_locked;
0318    }
0319 
0320    //!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
0321    //!   exception. Calls try_lock_until(abs_time) on the referenced mutex.
0322    //!Postconditions: owns() == the value returned from mutex()-> timed_lock(abs_time).
0323    //!Notes: The scoped_lock changes from a state of not owning the mutex, to
0324    //!   owning the mutex, but only if it can obtain ownership by the specified
0325    //!   time. If the mutex_type does not support timed_lock (), this function
0326    //!   will fail at compile time if instantiated, but otherwise have no effect.*/
0327    template<class TimePoint>
0328    bool try_lock_until(const TimePoint& abs_time)
0329    {
0330       if(!mp_mutex || m_locked)
0331          throw lock_exception();
0332       m_locked = mp_mutex->try_lock_until(abs_time);
0333       return m_locked;
0334    }
0335 
0336    //!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
0337    //!   exception. Calls try_lock_until(abs_time) on the referenced mutex.
0338    //!Postconditions: owns() == the value returned from mutex()-> timed_lock(abs_time).
0339    //!Notes: The scoped_lock changes from a state of not owning the mutex, to
0340    //!   owning the mutex, but only if it can obtain ownership by the specified
0341    //!   time. If the mutex_type does not support timed_lock (), this function
0342    //!   will fail at compile time if instantiated, but otherwise have no effect.*/
0343    template<class Duration>
0344    bool try_lock_for(const Duration& dur)
0345    {
0346       if(!mp_mutex || m_locked)
0347          throw lock_exception();
0348       m_locked = mp_mutex->try_lock_for(dur);
0349       return m_locked;
0350    }
0351 
0352    //!Effects: If mutex() == 0 or if not locked, throws a lock_exception()
0353    //!   exception. Calls unlock() on the referenced mutex.
0354    //!Postconditions: owns() == false.
0355    //!Notes: The scoped_lock changes from a state of owning the mutex, to not
0356    //!   owning the mutex.*/
0357    void unlock()
0358    {
0359       if(!mp_mutex || !m_locked)
0360          throw lock_exception();
0361       mp_mutex->unlock();
0362       m_locked = false;
0363    }
0364 
0365    //!Effects: Returns true if this scoped_lock has acquired
0366    //!the referenced mutex.
0367    bool owns() const BOOST_NOEXCEPT
0368    {  return m_locked && mp_mutex;  }
0369 
0370    //!Conversion to bool.
0371    //!Returns owns().
0372    operator unspecified_bool_type() const BOOST_NOEXCEPT
0373    {  return m_locked? &this_type::m_locked : 0;   }
0374 
0375    //!Effects: Returns a pointer to the referenced mutex, or 0 if
0376    //!there is no mutex to reference.
0377    mutex_type* mutex() const BOOST_NOEXCEPT
0378    {  return  mp_mutex;  }
0379 
0380    //!Effects: Returns a pointer to the referenced mutex, or 0 if there is no
0381    //!   mutex to reference.
0382    //!Postconditions: mutex() == 0 and owns() == false.
0383    mutex_type* release() BOOST_NOEXCEPT
0384    {
0385       mutex_type *mut = mp_mutex;
0386       mp_mutex = 0;
0387       m_locked = false;
0388       return mut;
0389    }
0390 
0391    //!Effects: Swaps state with moved lock.
0392    //!Throws: Nothing.
0393    void swap( scoped_lock<mutex_type> &other) BOOST_NOEXCEPT
0394    {
0395       (simple_swap)(mp_mutex, other.mp_mutex);
0396       (simple_swap)(m_locked, other.m_locked);
0397    }
0398 
0399    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
0400    private:
0401    mutex_type *mp_mutex;
0402    bool        m_locked;
0403    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
0404 };
0405 
0406 } // namespace interprocess
0407 } // namespace boost
0408 
0409 #include <boost/interprocess/detail/config_end.hpp>
0410 
0411 #endif // BOOST_INTERPROCESS_SCOPED_LOCK_HPP