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