PageRenderTime 31ms CodeModel.GetById 14ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Dependencies/Boost/boost/interprocess/sync/scoped_lock.hpp

http://hadesmem.googlecode.com/
C++ Header | 372 lines | 170 code | 34 blank | 168 comment | 23 complexity | db02c73d3e5f5b24fe8d38b525d94767 MD5 | raw file
  1//////////////////////////////////////////////////////////////////////////////
  2//
  3// (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost
  4// Software License, Version 1.0. (See accompanying file
  5// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6//
  7// See http://www.boost.org/libs/interprocess for documentation.
  8//
  9//////////////////////////////////////////////////////////////////////////////
 10//
 11// This interface is inspired by Howard Hinnant's lock proposal.
 12// http://home.twcny.rr.com/hinnant/cpp_extensions/threads_move.html
 13//
 14//////////////////////////////////////////////////////////////////////////////
 15
 16#ifndef BOOST_INTERPROCESS_SCOPED_LOCK_HPP
 17#define BOOST_INTERPROCESS_SCOPED_LOCK_HPP
 18
 19#if (defined _MSC_VER) && (_MSC_VER >= 1200)
 20#  pragma once
 21#endif
 22
 23#include <boost/interprocess/detail/config_begin.hpp>
 24#include <boost/interprocess/detail/workaround.hpp>
 25#include <boost/interprocess/interprocess_fwd.hpp>
 26#include <boost/interprocess/sync/lock_options.hpp>
 27#include <boost/interprocess/exceptions.hpp>
 28#include <boost/interprocess/detail/mpl.hpp>
 29#include <boost/interprocess/detail/type_traits.hpp>
 30#include <boost/interprocess/detail/move.hpp>
 31#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
 32
 33//!\file
 34//!Describes the scoped_lock class.
 35
 36namespace boost {
 37namespace interprocess {
 38
 39
 40//!scoped_lock is meant to carry out the tasks for locking, unlocking, try-locking
 41//!and timed-locking (recursive or not) for the Mutex. The Mutex need not supply all
 42//!of this functionality. If the client of scoped_lock<Mutex> does not use
 43//!functionality which the Mutex does not supply, no harm is done. Mutex ownership
 44//!transfer is supported through the syntax of move semantics. Ownership transfer
 45//!is allowed both by construction and assignment. The scoped_lock does not support
 46//!copy semantics. A compile time error results if copy construction or copy
 47//!assignment is attempted. Mutex ownership can also be moved from an
 48//!upgradable_lock and sharable_lock via constructor. In this role, scoped_lock
 49//!shares the same functionality as a write_lock.
 50template <class Mutex>
 51class scoped_lock
 52{
 53   /// @cond
 54   private:
 55   typedef scoped_lock<Mutex> this_type;
 56   BOOST_INTERPROCESS_MOVABLE_BUT_NOT_COPYABLE(scoped_lock)
 57   typedef bool this_type::*unspecified_bool_type;
 58   /// @endcond
 59   public:
 60
 61   typedef Mutex mutex_type;
 62
 63   //!Effects: Default constructs a scoped_lock.
 64   //!Postconditions: owns() == false and mutex() == 0.
 65   scoped_lock()
 66      : mp_mutex(0), m_locked(false)
 67   {}
 68
 69   //!Effects: m.lock().
 70   //!Postconditions: owns() == true and mutex() == &m.
 71   //!Notes: The constructor will take ownership of the mutex. If another thread
 72   //!   already owns the mutex, this thread will block until the mutex is released.
 73   //!   Whether or not this constructor handles recursive locking depends upon the mutex.
 74   explicit scoped_lock(mutex_type& m)
 75      : mp_mutex(&m), m_locked(false)
 76   {  mp_mutex->lock();   m_locked = true;  }
 77
 78   //!Postconditions: owns() == false, and mutex() == &m.
 79   //!Notes: The constructor will not take ownership of the mutex. There is no effect
 80   //!   required on the referenced mutex.
 81   scoped_lock(mutex_type& m, defer_lock_type)
 82      : mp_mutex(&m), m_locked(false)
 83   {}
 84
 85   //!Postconditions: owns() == true, and mutex() == &m.
 86   //!Notes: The constructor will suppose that the mutex is already locked. There
 87   //!   is no effect required on the referenced mutex.
 88   scoped_lock(mutex_type& m, accept_ownership_type)
 89      : mp_mutex(&m), m_locked(true)
 90   {}
 91
 92   //!Effects: m.try_lock(). 
 93   //!Postconditions: mutex() == &m. owns() == the return value of the
 94   //!   m.try_lock() executed within the constructor.
 95   //!Notes: The constructor will take ownership of the mutex if it can do
 96   //!   so without waiting. Whether or not this constructor handles recursive
 97   //!   locking depends upon the mutex. If the mutex_type does not support try_lock,
 98   //!   this constructor will fail at compile time if instantiated, but otherwise
 99   //!   have no effect.
100   scoped_lock(mutex_type& m, try_to_lock_type)
101      : mp_mutex(&m), m_locked(mp_mutex->try_lock())
102   {}
103
104   //!Effects: m.timed_lock(abs_time). 
105   //!Postconditions: mutex() == &m. owns() == the return value of the
106   //!   m.timed_lock(abs_time) executed within the constructor.
107   //!Notes: The constructor will take ownership of the mutex if it can do
108   //!   it until abs_time is reached. Whether or not this constructor
109   //!   handles recursive locking depends upon the mutex. If the mutex_type
110   //!   does not support try_lock, this constructor will fail at compile
111   //!   time if instantiated, but otherwise have no effect.
112   scoped_lock(mutex_type& m, const boost::posix_time::ptime& abs_time)
113      : mp_mutex(&m), m_locked(mp_mutex->timed_lock(abs_time))
114   {}
115
116   //!Postconditions: mutex() == the value scop.mutex() had before the
117   //!   constructor executes. s1.mutex() == 0. owns() == the value of
118   //!   scop.owns() before the constructor executes. scop.owns().
119   //!Notes: If the scop scoped_lock owns the mutex, ownership is moved
120   //!   to thisscoped_lock with no blocking. If the scop scoped_lock does not
121   //!   own the mutex, then neither will this scoped_lock. Only a moved
122   //!   scoped_lock's will match this signature. An non-moved scoped_lock
123   //!   can be moved with the expression: "boost::interprocess::move(lock);". This
124   //!   constructor does not alter the state of the mutex, only potentially
125   //!   who owns it.
126   scoped_lock(BOOST_INTERPROCESS_RV_REF(scoped_lock) scop)
127      : mp_mutex(0), m_locked(scop.owns())
128   {  mp_mutex = scop.release(); }
129
130   //!Effects: If upgr.owns() then calls unlock_upgradable_and_lock() on the
131   //!   referenced mutex. upgr.release() is called. 
132   //!Postconditions: mutex() == the value upgr.mutex() had before the construction.
133   //!   upgr.mutex() == 0. owns() == upgr.owns() before the construction.
134   //!   upgr.owns() == false after the construction.
135   //!Notes: If upgr is locked, this constructor will lock this scoped_lock while
136   //!   unlocking upgr. If upgr is unlocked, then this scoped_lock will be
137   //!   unlocked as well. Only a moved upgradable_lock's will match this
138   //!   signature. An non-moved upgradable_lock can be moved with
139   //!   the expression: "boost::interprocess::move(lock);" This constructor may block if
140   //!   other threads hold a sharable_lock on this mutex (sharable_lock's can
141   //!   share ownership with an upgradable_lock).
142   template<class T>
143   explicit scoped_lock(BOOST_INTERPROCESS_RV_REF(upgradable_lock<T>) upgr
144      , typename detail::enable_if< detail::is_same<T, Mutex> >::type * = 0)
145      : mp_mutex(0), m_locked(false)
146   {
147      upgradable_lock<mutex_type> &u_lock = upgr;
148      if(u_lock.owns()){
149         u_lock.mutex()->unlock_upgradable_and_lock();
150         m_locked = true;
151      }
152      mp_mutex = u_lock.release();
153   }
154
155   //!Effects: If upgr.owns() then calls try_unlock_upgradable_and_lock() on the
156   //!referenced mutex:
157   //!   a)if try_unlock_upgradable_and_lock() returns true then mutex() obtains
158   //!      the value from upgr.release() and owns() is set to true. 
159   //!   b)if try_unlock_upgradable_and_lock() returns false then upgr is
160   //!      unaffected and this scoped_lock construction as the same effects as  
161   //!      a default construction. 
162   //!   c)Else upgr.owns() is false. mutex() obtains the value from upgr.release()
163   //!      and owns() is set to false 
164   //!Notes: This construction will not block. It will try to obtain mutex
165   //!   ownership from upgr immediately, while changing the lock type from a
166   //!   "read lock" to a "write lock". If the "read lock" isn't held in the
167   //!   first place, the mutex merely changes type to an unlocked "write lock".
168   //!   If the "read lock" is held, then mutex transfer occurs only if it can
169   //!   do so in a non-blocking manner.
170   template<class T>
171   scoped_lock(BOOST_INTERPROCESS_RV_REF(upgradable_lock<T>) upgr, try_to_lock_type
172         , typename detail::enable_if< detail::is_same<T, Mutex> >::type * = 0)
173      : mp_mutex(0), m_locked(false)
174   {
175      upgradable_lock<mutex_type> &u_lock = upgr;
176      if(u_lock.owns()){
177         if((m_locked = u_lock.mutex()->try_unlock_upgradable_and_lock()) == true){
178            mp_mutex = u_lock.release();
179         }
180      }
181      else{
182         u_lock.release();
183      }
184   }
185
186   //!Effects: If upgr.owns() then calls timed_unlock_upgradable_and_lock(abs_time)
187   //!   on the referenced mutex:
188   //!   a)if timed_unlock_upgradable_and_lock(abs_time) returns true then mutex()
189   //!      obtains the value from upgr.release() and owns() is set to true. 
190   //!   b)if timed_unlock_upgradable_and_lock(abs_time) returns false then upgr
191   //!      is unaffected and this scoped_lock construction as the same effects
192   //!      as a default construction.
193   //!   c)Else upgr.owns() is false. mutex() obtains the value from upgr.release()
194   //!      and owns() is set to false 
195   //!Notes: This construction will not block. It will try to obtain mutex ownership
196   //!   from upgr immediately, while changing the lock type from a "read lock" to a
197   //!   "write lock". If the "read lock" isn't held in the first place, the mutex
198   //!   merely changes type to an unlocked "write lock". If the "read lock" is held,
199   //!   then mutex transfer occurs only if it can do so in a non-blocking manner.
200   template<class T>
201   scoped_lock(BOOST_INTERPROCESS_RV_REF(upgradable_lock<T>) upgr, boost::posix_time::ptime &abs_time
202               , typename detail::enable_if< detail::is_same<T, Mutex> >::type * = 0)
203      : mp_mutex(0), m_locked(false)
204   {
205      upgradable_lock<mutex_type> &u_lock = upgr;
206      if(u_lock.owns()){
207         if((m_locked = u_lock.mutex()->timed_unlock_upgradable_and_lock(abs_time)) == true){
208            mp_mutex = u_lock.release();
209         }
210      }
211      else{
212         u_lock.release();
213      }
214   }
215
216   //!Effects: If shar.owns() then calls try_unlock_sharable_and_lock() on the
217   //!referenced mutex. 
218   //!   a)if try_unlock_sharable_and_lock() returns true then mutex() obtains
219   //!      the value from shar.release() and owns() is set to true. 
220   //!   b)if try_unlock_sharable_and_lock() returns false then shar is
221   //!      unaffected and this scoped_lock construction has the same
222   //!      effects as a default construction. 
223   //!   c)Else shar.owns() is false. mutex() obtains the value from
224   //!      shar.release() and owns() is set to false 
225   //!Notes: This construction will not block. It will try to obtain mutex
226   //!   ownership from shar immediately, while changing the lock type from a
227   //!   "read lock" to a "write lock". If the "read lock" isn't held in the
228   //!   first place, the mutex merely changes type to an unlocked "write lock".
229   //!   If the "read lock" is held, then mutex transfer occurs only if it can
230   //!   do so in a non-blocking manner.
231   template<class T>
232   scoped_lock(BOOST_INTERPROCESS_RV_REF(sharable_lock<T>) shar, try_to_lock_type
233      , typename detail::enable_if< detail::is_same<T, Mutex> >::type * = 0)
234      : mp_mutex(0), m_locked(false)
235   {
236      sharable_lock<mutex_type> &s_lock = shar;
237      if(s_lock.owns()){
238         if((m_locked = s_lock.mutex()->try_unlock_sharable_and_lock()) == true){
239            mp_mutex = s_lock.release();
240         }
241      }
242      else{
243         s_lock.release();
244      }
245   }
246
247   //!Effects: if (owns()) mp_mutex->unlock().
248   //!Notes: The destructor behavior ensures that the mutex lock is not leaked.*/
249   ~scoped_lock()
250   {
251      try{  if(m_locked && mp_mutex)   mp_mutex->unlock();  }
252      catch(...){}
253   }
254
255   //!Effects: If owns() before the call, then unlock() is called on mutex().
256   //!   *this gets the state of scop and scop gets set to a default constructed state. 
257   //!Notes: With a recursive mutex it is possible that both this and scop own
258   //!   the same mutex before the assignment. In this case, this will own the
259   //!   mutex after the assignment (and scop will not), but the mutex's lock
260   //!   count will be decremented by one.
261   scoped_lock &operator=(BOOST_INTERPROCESS_RV_REF(scoped_lock) scop)
262   {  
263      if(this->owns())
264         this->unlock();
265      m_locked = scop.owns();
266      mp_mutex = scop.release();
267      return *this;
268   }
269
270   //!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
271   //!   exception. Calls lock() on the referenced mutex.
272   //!Postconditions: owns() == true.
273   //!Notes: The scoped_lock changes from a state of not owning the mutex, to
274   //!   owning the mutex, blocking if necessary.
275   void lock()
276   {
277      if(!mp_mutex || m_locked)
278         throw lock_exception();
279      mp_mutex->lock();
280      m_locked = true;
281   }
282
283   //!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
284   //!   exception. Calls try_lock() on the referenced mutex. 
285   //!Postconditions: owns() == the value returned from mutex()->try_lock().
286   //!Notes: The scoped_lock changes from a state of not owning the mutex, to
287   //!   owning the mutex, but only if blocking was not required. If the
288   //!   mutex_type does not support try_lock(), this function will fail at
289   //!   compile time if instantiated, but otherwise have no effect.*/
290   bool try_lock()
291   {
292      if(!mp_mutex || m_locked)
293         throw lock_exception();
294      m_locked = mp_mutex->try_lock();
295      return m_locked;
296   }
297
298   //!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
299   //!   exception. Calls timed_lock(abs_time) on the referenced mutex.
300   //!Postconditions: owns() == the value returned from mutex()-> timed_lock(abs_time).
301   //!Notes: The scoped_lock changes from a state of not owning the mutex, to
302   //!   owning the mutex, but only if it can obtain ownership by the specified
303   //!   time. If the mutex_type does not support timed_lock (), this function
304   //!   will fail at compile time if instantiated, but otherwise have no effect.*/
305   bool timed_lock(const boost::posix_time::ptime& abs_time)
306   {
307      if(!mp_mutex || m_locked)
308         throw lock_exception();
309      m_locked = mp_mutex->timed_lock(abs_time);
310      return m_locked;
311   }
312
313   //!Effects: If mutex() == 0 or if not locked, throws a lock_exception()
314   //!   exception. Calls unlock() on the referenced mutex.
315   //!Postconditions: owns() == false.
316   //!Notes: The scoped_lock changes from a state of owning the mutex, to not
317   //!   owning the mutex.*/
318   void unlock()
319   {
320      if(!mp_mutex || !m_locked)
321         throw lock_exception();
322      mp_mutex->unlock();
323      m_locked = false;
324   }
325
326   //!Effects: Returns true if this scoped_lock has acquired
327   //!the referenced mutex.
328   bool owns() const
329   {  return m_locked && mp_mutex;  }
330
331   //!Conversion to bool.
332   //!Returns owns().
333   operator unspecified_bool_type() const
334   {  return m_locked? &this_type::m_locked : 0;   }
335
336   //!Effects: Returns a pointer to the referenced mutex, or 0 if
337   //!there is no mutex to reference.
338   mutex_type* mutex() const
339   {  return  mp_mutex;  }
340
341   //!Effects: Returns a pointer to the referenced mutex, or 0 if there is no
342   //!   mutex to reference.
343   //!Postconditions: mutex() == 0 and owns() == false.
344   mutex_type* release()
345   {
346      mutex_type *mut = mp_mutex;
347      mp_mutex = 0;
348      m_locked = false;
349      return mut;
350   }
351 
352   //!Effects: Swaps state with moved lock. 
353   //!Throws: Nothing.
354   void swap( scoped_lock<mutex_type> &other)
355   {
356      std::swap(mp_mutex, other.mp_mutex);
357      std::swap(m_locked, other.m_locked);
358   }
359
360   /// @cond
361   private:
362   mutex_type *mp_mutex; 
363   bool        m_locked;
364   /// @endcond
365};
366
367} // namespace interprocess
368} // namespace boost
369
370#include <boost/interprocess/detail/config_end.hpp>
371
372#endif // BOOST_INTERPROCESS_SCOPED_LOCK_HPP