include/corelib/guard.hpp

Go to the documentation of this file.
00001 #ifndef CORELIB___GUARD__HPP
00002 #define CORELIB___GUARD__HPP
00003 
00004 /*  $Id: guard.hpp 103491 2007-05-04 17:18:18Z kazimird $
00005  * ===========================================================================
00006  *
00007  *                            PUBLIC DOMAIN NOTICE
00008  *               National Center for Biotechnology Information
00009  *
00010  *  This software/database is a "United States Government Work" under the
00011  *  terms of the United States Copyright Act.  It was written as part of
00012  *  the author's official duties as a United States Government employee and
00013  *  thus cannot be copyrighted.  This software/database is freely available
00014  *  to the public for use. The National Library of Medicine and the U.S.
00015  *  Government have not placed any restriction on its use or reproduction.
00016  *
00017  *  Although all reasonable efforts have been taken to ensure the accuracy
00018  *  and reliability of the software and data, the NLM and the U.S.
00019  *  Government do not and cannot warrant the performance or results that
00020  *  may be obtained by using this software or data. The NLM and the U.S.
00021  *  Government disclaim all warranties, express or implied, including
00022  *  warranties of performance, merchantability or fitness for any particular
00023  *  purpose.
00024  *
00025  *  Please cite the author in any work or product based on this material.
00026  *
00027  * ===========================================================================
00028  *
00029  * Authors:  Mike DiCuccio
00030  *
00031  * File Description:
00032  *     CGuard<> -- implementation of RAII-based locking guard
00033  *
00034  */
00035 
00036 #include <corelib/ncbidbg.hpp>
00037 
00038 
00039 BEGIN_NCBI_SCOPE
00040 
00041 
00042 ///
00043 /// SSimpleLock is a functor to wrap calling Lock().  While this may seem
00044 /// excessive, it permits a lot of flexibility in defining what it means
00045 /// to acquire a lock
00046 ///
00047 template <class Resource>
00048 struct SSimpleLock
00049 {
00050     typedef Resource resource_type;
00051     void operator()(resource_type& resource) const
00052     {
00053         resource.Lock();
00054     }
00055 };
00056 
00057 
00058 ///
00059 /// SSimpleLock is a functor to wrap calling Unlock().  While this may seem
00060 /// excessive, it permits a lot of flexibility in defining what it means
00061 /// to release a lock
00062 ///
00063 template <class Resource>
00064 struct SSimpleUnlock
00065 {
00066     typedef Resource resource_type;
00067     void operator()(resource_type& resource) const
00068     {
00069         resource.Unlock();
00070     }
00071 };
00072 
00073 
00074 ///
00075 /// class CGuard<> implements a templatized "resource acquisition is
00076 /// initialization" (RAII) locking guard.
00077 ///
00078 /// This guard is useful for locking resources in an exception-safe manner.
00079 /// The classic use of this is to lock a mutex within a C++ scope, as follows:
00080 ///
00081 /// void SomeFunction()
00082 /// {
00083 ///     CGuard<CMutex> GUARD(some_mutex);
00084 ///     [...perform some thread-safe operations...]
00085 /// }
00086 ///
00087 /// If an exception is thrown during the performance of any operations while
00088 /// the guard is held, the guarantee of C++ stack-unwinding will force
00089 /// the guard's destructor to release whatever resources were acquired.
00090 ///
00091 ///
00092 
00093 enum EEmptyGuard {
00094     eEmptyGuard
00095 };
00096 
00097 template <class Resource,
00098           class Lock = SSimpleLock<Resource>,
00099           class Unlock = SSimpleUnlock<Resource> >
00100 class CGuard
00101 {
00102 public:
00103     typedef Resource resource_type;
00104     typedef resource_type* resource_ptr;
00105     typedef Lock lock_type;
00106     typedef Unlock unlock_type;
00107     typedef CGuard<Resource, Lock, Unlock> TThisType;
00108 
00109     explicit CGuard(EEmptyGuard /*empty*/)
00110         {
00111         }
00112     
00113     /// This constructor locks the resource passed.
00114     explicit CGuard(resource_type& resource)
00115         {
00116             Guard(resource);
00117         }
00118     
00119     explicit CGuard(EEmptyGuard /*empty*/,
00120                     const lock_type& lock,
00121                     const unlock_type& unlock = unlock_type())
00122         : m_Data(lock, pair_base_member<unlock_type, resource_ptr>(unlock, 0))
00123         {
00124         }
00125     
00126     /// This constructor locks the resource passed.
00127     explicit CGuard(resource_type& resource,
00128                     const lock_type& lock,
00129                     const unlock_type& unlock = unlock_type())
00130         : m_Data(lock, pair_base_member<unlock_type, resource_ptr>(unlock, 0))
00131         {
00132             Guard(resource);
00133         }
00134     
00135     /// Destructor releases the resource.
00136     ~CGuard()
00137         {
00138             try {
00139                 Release();
00140             } catch(std::exception& ) {
00141                 // catch and ignore std exceptions in destructor
00142             }
00143         }
00144     
00145     /// Manually force the resource to be released.
00146     void Release()
00147         {
00148             if ( GetResource() ) {
00149                 GetUnlock()(*GetResource());
00150                 GetResource() = 0;
00151             }
00152         }
00153     
00154     /// Manually force the guard to protect some other resource.
00155     void Guard(resource_type& resource)
00156         {
00157             Release();
00158             GetLock()(resource);
00159             GetResource() = &resource;
00160         }
00161     
00162 protected:
00163     resource_ptr& GetResource(void)
00164         {
00165             return m_Data.second().second();
00166         }
00167     lock_type& GetLock(void)
00168         {
00169             return m_Data.first();
00170         }
00171     unlock_type& GetUnlock(void)
00172         {
00173             return m_Data.second().first();
00174         }
00175 
00176 private:
00177     /// Maintain a pointer to the original resource that is being guarded
00178     pair_base_member<lock_type,
00179                      pair_base_member<unlock_type,
00180                                       resource_ptr> >  m_Data;
00181 
00182 private:
00183     // prevent copying
00184     CGuard(const CGuard<resource_type, lock_type, unlock_type>&);
00185     void operator=(const CGuard<resource_type, lock_type, unlock_type>&);
00186 };
00187 
00188 
00189 ///
00190 /// CNoLock is a simple no-op lock which does no real locking.
00191 /// The class can be used as a template argument instead of normal
00192 /// locks (e.g. CMutex).
00193 ///
00194 class CNoLock
00195 {
00196 public:
00197     typedef CGuard<CNoLock> TReadLockGuard;
00198     typedef CGuard<CNoLock> TWriteLockGuard;
00199 
00200     void Lock  (void) const {}
00201     void Unlock(void) const {}
00202 };
00203 
00204 
00205 END_NCBI_SCOPE
00206 
00207 #endif  // CORELIB___GUARD__HPP
00208 
00209 

Generated on Sun Dec 6 21:58:39 2009 for NCBI C++ ToolKit by  doxygen 1.4.6
Modified on Mon Dec 07 16:20:34 2009 by modify_doxy.py rev. 173732