ncbi_safe_static.hpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:12k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbi_safe_static.hpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 19:07:46  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.12
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. #ifndef NCBI_SAFE_STATIC__HPP
  10. #define NCBI_SAFE_STATIC__HPP
  11. /*  $Id: ncbi_safe_static.hpp,v 1000.1 2004/06/01 19:07:46 gouriano Exp $
  12.  * ===========================================================================
  13.  *
  14.  *                            PUBLIC DOMAIN NOTICE
  15.  *               National Center for Biotechnology Information
  16.  *
  17.  *  This software/database is a "United States Government Work" under the
  18.  *  terms of the United States Copyright Act.  It was written as part of
  19.  *  the author's official duties as a United States Government employee and
  20.  *  thus cannot be copyrighted.  This software/database is freely available
  21.  *  to the public for use. The National Library of Medicine and the U.S.
  22.  *  Government have not placed any restriction on its use or reproduction.
  23.  *
  24.  *  Although all reasonable efforts have been taken to ensure the accuracy
  25.  *  and reliability of the software and data, the NLM and the U.S.
  26.  *  Government do not and cannot warrant the performance or results that
  27.  *  may be obtained by using this software or data. The NLM and the U.S.
  28.  *  Government disclaim all warranties, express or implied, including
  29.  *  warranties of performance, merchantability or fitness for any particular
  30.  *  purpose.
  31.  *
  32.  *  Please cite the author in any work or product based on this material.
  33.  *
  34.  * ===========================================================================
  35.  *
  36.  * Author:   Aleksey Grichenko
  37.  *
  38.  * File Description:
  39.  *   Static variables safety - create on demand, destroy on termination
  40.  *
  41.  *   CSafeStaticPtr_Base::   --  base class for CSafePtr<> and CSafeRef<>
  42.  *   CSafeStaticPtr<>::      -- create variable on demand, destroy on program
  43.  *                              termination (see NCBIOBJ for CSafeRef<> class)
  44.  *   CSafeStaticRef<>::      -- create variable on demand, destroy on program
  45.  *                              termination (see NCBIOBJ for CSafeRef<> class)
  46.  *   CSafeStaticGuard::      -- guarantee for CSafePtr<> and CSafeRef<>
  47.  *                              destruction and cleanup
  48.  *
  49.  */
  50. #include <corelib/ncbistl.hpp>
  51. #include <corelib/ncbiobj.hpp>
  52. #include <corelib/ncbithr.hpp>
  53. #include <stack>
  54. BEGIN_NCBI_SCOPE
  55. /////////////////////////////////////////////////////////////////////////////
  56. //
  57. //  CSafeStaticPtr_Base::
  58. //
  59. //    Base class for CSafeStaticPtr<> and CSafeStaticRef<> templates.
  60. //
  61. // Base class for CSafeStaticPtr<> and CSafeStaticRef<> templates
  62. class NCBI_XNCBI_EXPORT CSafeStaticPtr_Base
  63. {
  64. public:
  65.     // User cleanup function type
  66.     typedef void (*FSelfCleanup)(void** ptr);
  67.     typedef void (*FUserCleanup)(void*  ptr);
  68.     // Set user-provided cleanup function to be executed on destruction
  69.     CSafeStaticPtr_Base(FSelfCleanup self_cleanup,
  70.                         FUserCleanup user_cleanup = 0)
  71.         : m_SelfCleanup(self_cleanup),
  72.           m_UserCleanup(user_cleanup)
  73.     {}
  74. protected:
  75.     void* m_Ptr;          // Pointer to the data
  76.     // Prepare to the object initialization: check current thread, lock
  77.     // the mutex and store its state to "mutex_locked", return "true"
  78.     // if the object must be created or "false" if already created.
  79.     bool Init_Lock(bool* mutex_locked);
  80.     // Finalize object initialization: release the mutex if "mutex_locked"
  81.     void Init_Unlock(bool mutex_locked);
  82. private:
  83.     FSelfCleanup m_SelfCleanup;  // Derived class' cleanup function
  84.     FUserCleanup m_UserCleanup;  // User-provided  cleanup function
  85.     // To be called by CSafeStaticGuard on the program termination
  86.     friend class CSafeStaticGuard;
  87.     void Cleanup(void)
  88.     {
  89.         if ( m_UserCleanup )  m_UserCleanup(m_Ptr);
  90.         if ( m_SelfCleanup )  m_SelfCleanup(&m_Ptr);
  91.     }
  92. };
  93. /////////////////////////////////////////////////////////////////////////////
  94. //
  95. //  CSafeStaticPtr<>::
  96. //
  97. //    For simple on-demand variables.
  98. //    Create the variable of type "T" on demand,
  99. //    destroy it on the program termination.
  100. //
  101. template <class T>
  102. class CSafeStaticPtr : public CSafeStaticPtr_Base
  103. {
  104. public:
  105.     // Set the cleanup function to be called on variable destruction
  106.     CSafeStaticPtr(FUserCleanup user_cleanup = 0)
  107.         : CSafeStaticPtr_Base(SelfCleanup, user_cleanup)
  108.     {}
  109.     // Create the variable if not created yet, return the reference
  110.     T& Get(void)
  111.     {
  112.         if ( !m_Ptr ) {
  113.             Init();
  114.         }
  115.         return *static_cast<T*> (m_Ptr);
  116.     }
  117.     T* operator -> (void) { return &Get(); }
  118.     T& operator *  (void) { return  Get(); }
  119.     // Initialize with an existing object. The object MUST be
  120.     // allocated with "new T" -- it will be destroyed with
  121.     // "delete object" in the end. Set() works only for
  122.     // not yet initialized safe-static variables.
  123.     void Set(T* object);
  124. private:
  125.     // Initialize the object
  126.     void Init(void);
  127.     // "virtual" cleanup function
  128.     static void SelfCleanup(void** ptr)
  129.     {
  130.         T* tmp = static_cast<T*> (*ptr);
  131.         *ptr = 0;
  132.         delete tmp;
  133.     }
  134. };
  135. /////////////////////////////////////////////////////////////////////////////
  136. //
  137. //  CSafeStaticRef<>::
  138. //
  139. //    For on-demand CObject-derived object.
  140. //    Create the variable of type "T" using CRef<>
  141. //    (to avoid premature destruction).
  142. //
  143. template <class T>
  144. class CSafeStaticRef : public CSafeStaticPtr_Base
  145. {
  146. public:
  147.     // Set the cleanup function to be called on variable destruction
  148.     CSafeStaticRef(FUserCleanup user_cleanup = 0)
  149.         : CSafeStaticPtr_Base(SelfCleanup, user_cleanup)
  150.     {}
  151.     // Create the variable if not created yet, return the reference
  152.     T& Get(void)
  153.     {
  154.         if ( !m_Ptr ) {
  155.             Init();
  156.         }
  157.         return static_cast<CRef<T>*> (m_Ptr)->GetObject();
  158.     }
  159.     T* operator -> (void) { return &Get(); }
  160.     T& operator *  (void) { return  Get(); }
  161.     // Initialize with an existing object. The object MUST be
  162.     // allocated with "new T" to avoid premature destruction.
  163.     // Set() works only for un-initialized safe-static variables.
  164.     void Set(T* object);
  165. private:
  166.     // Initialize the object and the reference
  167.     void Init(void);
  168.     // "virtual" cleanup function
  169.     static void SelfCleanup(void** ptr)
  170.     {
  171.         CRef<T>* tmp = static_cast< CRef<T>* > (*ptr);
  172.         *ptr = 0;
  173.         delete tmp;
  174.     }
  175. };
  176. /////////////////////////////////////////////////////////////////////////////
  177. //
  178. //  CSafeStaticGuard::
  179. //
  180. //    Register all on-demand variables,
  181. //    destroy them on the program termination.
  182. class NCBI_XNCBI_EXPORT CSafeStaticGuard
  183. {
  184. public:
  185.     // Check if already initialized. If not - create the stack,
  186.     // otherwise just increment the reference count.
  187.     CSafeStaticGuard(void);
  188.     // Check reference count, and if it is zero, then destroy
  189.     // all registered variables.
  190.     ~CSafeStaticGuard(void);
  191.     // Add new on-demand variable to the cleanup stack.
  192.     static void Register(CSafeStaticPtr_Base* ptr)
  193.     {
  194.         if ( !sm_Stack ) {
  195.             Get();
  196.         }
  197.         sm_Stack->push(ptr);
  198.     }
  199. private:
  200.     // Initialize the guard, return pointer to it.
  201.     static CSafeStaticGuard* Get(void);
  202.     // Stack to keep registered variables.
  203.     typedef stack<CSafeStaticPtr_Base*> TStack;
  204.     static TStack* sm_Stack;
  205.     // Reference counter. The stack is destroyed when
  206.     // the last reference is removed.
  207.     static int sm_RefCount;
  208. };
  209. /////////////////////////////////////////////////////////////////////////////
  210. //
  211. // This static variable must be present in all modules using
  212. // on-demand variables. The guard must be created first
  213. // regardless of the modules initialization order.
  214. //
  215. static CSafeStaticGuard s_CleanupGuard;
  216. /////////////////////////////////////////////////////////////////////////////
  217. //
  218. // Large inline methods
  219. template <class T>
  220. inline
  221. void CSafeStaticPtr<T>::Set(T* object)
  222. {
  223.     bool mutex_locked = false;
  224.     if ( Init_Lock(&mutex_locked) ) {
  225.         // Set the new object and register for cleanup
  226.         try {
  227.             m_Ptr = object;
  228.             CSafeStaticGuard::Register(this);
  229.         }
  230.         catch (CException& e) {
  231.             Init_Unlock(mutex_locked);
  232.             NCBI_RETHROW_SAME(e, "CSafeStaticPtr::Set: Register() failed");
  233.         }
  234.         catch (...) {
  235.             Init_Unlock(mutex_locked);
  236.             NCBI_THROW(CCoreException,eCore,
  237.                        "CSafeStaticPtr::Set: Register() failed");
  238.         }
  239.     }
  240.     Init_Unlock(mutex_locked);
  241. }
  242. template <class T>
  243. inline
  244. void CSafeStaticPtr<T>::Init(void)
  245. {
  246.     bool mutex_locked = false;
  247.     if ( Init_Lock(&mutex_locked) ) {
  248.         // Create the object and register for cleanup
  249.         try {
  250.             m_Ptr = new T;
  251.             CSafeStaticGuard::Register(this);
  252.         }
  253.         catch (CException& e) {
  254.             Init_Unlock(mutex_locked);
  255.             NCBI_RETHROW_SAME(e, "CSafeStaticPtr::Init: Register() failed");
  256.         }
  257.         catch (...) {
  258.             Init_Unlock(mutex_locked);
  259.             NCBI_THROW(CCoreException,eCore,
  260.                        "CSafeStaticPtr::Init: Register() failed");
  261.         }
  262.     }
  263.     Init_Unlock(mutex_locked);
  264. }
  265. template <class T>
  266. inline
  267. void CSafeStaticRef<T>::Set(T* object)
  268. {
  269.     bool mutex_locked = false;
  270.     if ( Init_Lock(&mutex_locked) ) {
  271.         // Set the new object and register for cleanup
  272.         try {
  273.             m_Ptr = new CRef<T> (object);
  274.             CSafeStaticGuard::Register(this);
  275.         }
  276.         catch (CException& e) {
  277.             Init_Unlock(mutex_locked);
  278.             NCBI_RETHROW_SAME(e, "CSafeStaticRef::Set: Register() failed");
  279.         }
  280.         catch (...) {
  281.             Init_Unlock(mutex_locked);
  282.             NCBI_THROW(CCoreException,eCore,
  283.                        "CSafeStaticRef::Set: Register() failed");
  284.         }
  285.     }
  286.     Init_Unlock(mutex_locked);
  287. }
  288. template <class T>
  289. inline
  290. void CSafeStaticRef<T>::Init(void)
  291. {
  292.     bool mutex_locked = false;
  293.     if ( Init_Lock(&mutex_locked) ) {
  294.         // Create the object and register for cleanup
  295.         try {
  296.             m_Ptr = new CRef<T> (new T);
  297.             CSafeStaticGuard::Register(this);
  298.         }
  299.         catch (CException& e) {
  300.             Init_Unlock(mutex_locked);
  301.             NCBI_RETHROW_SAME(e, "CSafeStaticRef::Init: Register() failed");
  302.         }
  303.         catch (...) {
  304.             Init_Unlock(mutex_locked);
  305.             NCBI_THROW(CCoreException,eCore,
  306.                        "CSafeStaticRef::Init: Register() failed");
  307.         }
  308.     }
  309.     Init_Unlock(mutex_locked);
  310. }
  311. END_NCBI_SCOPE
  312. /*
  313.  * ===========================================================================
  314.  * $Log: ncbi_safe_static.hpp,v $
  315.  * Revision 1000.1  2004/06/01 19:07:46  gouriano
  316.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.12
  317.  *
  318.  * Revision 1.12  2004/04/26 14:28:59  ucko
  319.  * Move large inline methods [Set(), Init()] from CSafeStatic{Ptr,Ref}'s
  320.  * definitions to the end of the file, both to reduce clutter and because
  321.  * GCC 3.4 insists on seeing CSafeStaticGuard first.
  322.  *
  323.  * Revision 1.11  2002/12/18 22:53:21  dicuccio
  324.  * Added export specifier for building DLLs in windows.  Added global list of
  325.  * all such specifiers in mswin_exports.hpp, included through ncbistl.hpp
  326.  *
  327.  * Revision 1.10  2002/09/19 20:05:41  vasilche
  328.  * Safe initialization of static mutexes
  329.  *
  330.  * Revision 1.9  2002/07/15 18:17:50  gouriano
  331.  * renamed CNcbiException and its descendents
  332.  *
  333.  * Revision 1.8  2002/07/11 14:17:53  gouriano
  334.  * exceptions replaced by CNcbiException-type ones
  335.  *
  336.  * Revision 1.7  2002/04/11 20:39:15  ivanov
  337.  * CVS log moved to end of the file
  338.  *
  339.  * Revision 1.6  2001/12/07 18:48:48  grichenk
  340.  * Improved CSafeStaticGuard behaviour.
  341.  *
  342.  * Revision 1.5  2001/08/24 13:42:37  grichenk
  343.  * Added CSafeStaticXXX::Set() methods for initialization with an
  344.  * existing object
  345.  *
  346.  * Revision 1.4  2001/04/06 15:45:26  grichenk
  347.  * Modified SelfCleanup() methods for more safety
  348.  *
  349.  * Revision 1.3  2001/03/30 23:10:10  grichenk
  350.  * Protected from double initializations and deadlocks in multithread
  351.  * environment
  352.  *
  353.  * Revision 1.2  2001/03/26 21:01:41  vakatov
  354.  * CSafeStaticPtr, CSafeStaticRef -- added "operator *"
  355.  *
  356.  * Revision 1.1  2001/03/26 20:38:33  vakatov
  357.  * Initial revision (by A.Grichenko)
  358.  *
  359.  * ===========================================================================
  360.  */
  361. #endif  /* NCBI_SAFE_STATIC__HPP */