|
|
|||
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
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|