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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbimtx.hpp,v $
  4.  * PRODUCTION Revision 1000.2  2004/04/21 14:34:52  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [CATCHUP_003] Dev-tree R1.35
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. #ifndef CORELIB___NCBIMTX__HPP
  10. #define CORELIB___NCBIMTX__HPP
  11. /*  $Id: ncbimtx.hpp,v 1000.2 2004/04/21 14:34:52 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:  Denis Vakatov, Aleksey Grichenko
  37.  *
  38.  *
  39.  */
  40. /// @file ncbimtx.hpp
  41. /// Multi-threading -- mutexes;  rw-locks; semaphore
  42. ///
  43. ///   MUTEX:
  44. ///
  45. /// MUTEX CLASSES:
  46. /// - SSystemFastMutex -- platform-dependent mutex functionality
  47. /// - SSystemMutex     -- platform-dependent mutex functionality
  48. /// - CFastMutex       -- simple mutex with fast lock/unlock functions
  49. /// - CMutex           -- mutex that allows nesting (with runtime checks)
  50. /// - CFastMutexGuard  -- acquire fast mutex, then guarantee for its release
  51. /// - CMutexGuard      -- acquire mutex, then guarantee for its release
  52. ///
  53. /// RW-LOCK:
  54. /// - CInternalRWLock  -- platform-dependent RW-lock structure (fwd-decl)
  55. /// - CRWLock          -- Read/Write lock related  data and methods
  56. /// - CAutoRW          -- guarantee RW-lock release
  57. /// - CReadLockGuard   -- acquire R-lock, then guarantee for its release
  58. /// - CWriteLockGuard  -- acquire W-lock, then guarantee for its release
  59. ///
  60. /// SEMAPHORE:
  61. /// - CSemaphore       -- application-wide semaphore
  62. ///
  63. #include <corelib/ncbithr_conf.hpp>
  64. #include <corelib/ncbicntr.hpp>
  65. #include <vector>
  66. #include <memory>
  67. /** @addtogroup Threads
  68.  *
  69.  * @{
  70.  */
  71. #if defined(_DEBUG)
  72. /// Mutex debug setting.
  73. #   define  INTERNAL_MUTEX_DEBUG
  74. #else
  75. #   undef   INTERNAL_MUTEX_DEBUG
  76. /// Mutex debug setting.
  77. #   define  INTERNAL_MUTEX_DEBUG
  78. #endif
  79. BEGIN_NCBI_SCOPE
  80. /////////////////////////////////////////////////////////////////////////////
  81. //
  82. // DECLARATIONS of internal (platform-dependent) representations
  83. //
  84. //    TMutex         -- internal mutex type
  85. //
  86. #if defined(NCBI_NO_THREADS)
  87. /// Define a platform independent system mutex.
  88. typedef int TSystemMutex; // fake
  89. # define SYSTEM_MUTEX_INITIALIZER 0
  90. #elif defined(NCBI_POSIX_THREADS)
  91. /// Define a platform independent system mutex.
  92. typedef pthread_mutex_t TSystemMutex;
  93. # define SYSTEM_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
  94. #elif defined(NCBI_WIN32_THREADS)
  95. /// Define a platform independent system mutex.
  96. typedef HANDLE TSystemMutex;
  97. # undef SYSTEM_MUTEX_INITIALIZER
  98. #else
  99. #  error Unknown threads type
  100. #endif
  101. /////////////////////////////////////////////////////////////////////////////
  102. ///
  103. /// CThreadSystemID --
  104. ///
  105. /// Define thread system ID.
  106. ///
  107. /// The CThreadSystemID is based on the platform dependent thread ID type,
  108. /// TThreadSystemID, defined in ncbithr_conf.hpp.
  109. class NCBI_XNCBI_EXPORT CThreadSystemID
  110. {
  111. public:
  112.     /// Define a simpler alias for TThreadSystemID.
  113.     typedef TThreadSystemID TID;
  114.     TID m_ID;           ///< Thread ID.
  115.     /// Get the current thread ID.
  116.     static CThreadSystemID GetCurrent(void)
  117.         {
  118.             CThreadSystemID id;
  119. #if defined(NCBI_NO_THREADS)
  120.             id.m_ID = TID(0);
  121. #elif defined(NCBI_POSIX_THREADS)
  122.             id.m_ID = pthread_self();
  123. #elif defined(NCBI_WIN32_THREADS)
  124.             id.m_ID = GetCurrentThreadId();
  125. #endif
  126.             return id;
  127.         }
  128.     /// Equality operator for thread ID.
  129.     bool operator==(const CThreadSystemID& id) const
  130.         {
  131.             return m_ID == id.m_ID;
  132.         }
  133.     /// Non-equality operator for thread ID.
  134.     bool operator!=(const CThreadSystemID& id) const
  135.         {
  136.             return m_ID != id.m_ID;
  137.         }
  138.     /// volatile versions of above methods
  139.     void Set(const CThreadSystemID& id) volatile
  140.         {
  141.             m_ID = id.m_ID;
  142.         }
  143.     bool Is(const CThreadSystemID& id) const volatile
  144.         {
  145.             return m_ID == id.m_ID;
  146.         }
  147.     bool IsNot(const CThreadSystemID& id) const volatile
  148.         {
  149.             return m_ID != id.m_ID;
  150.         }
  151. };
  152. /// Use in defining initial value of system mutex.
  153. #define THREAD_SYSTEM_ID_INITIALIZER { 0 }
  154. /////////////////////////////////////////////////////////////////////////////
  155. ///
  156. /// CMutexException --
  157. ///
  158. /// Define exceptions generated by mutexes.
  159. ///
  160. /// CMutexException inherits its basic functionality from CCoreException
  161. /// and defines additional error codes for applications.
  162. class NCBI_XNCBI_EXPORT CMutexException : public CCoreException
  163. {
  164. public:
  165.     /// Error types that a mutex can generate.
  166.     enum EErrCode {
  167.         eLock,          ///< Lock error
  168.         eUnlock,        ///< Unlock error
  169.         eTryLock,       ///< Attempted lock error
  170.         eOwner,         ///< Not owned error
  171.         eUninitialized  ///< Uninitialized error
  172.     };
  173.     /// Translate from the error code value to its string representation.
  174.     virtual const char* GetErrCodeString(void) const;
  175.     // Standard exception boilerplate code.
  176.     NCBI_EXCEPTION_DEFAULT(CMutexException,CCoreException);
  177. };
  178. /////////////////////////////////////////////////////////////////////////////
  179. //
  180. //  SYSTEM MUTEX
  181. //
  182. //    SSystemFastMutex
  183. //    SSystemMutex
  184. //
  185. class CFastMutex;
  186. class CFastMutexGuard;
  187. /////////////////////////////////////////////////////////////////////////////
  188. ///
  189. /// SSystemFastMutex --
  190. ///
  191. /// Define system fast mutex.
  192. ///
  193. /// Internal platform-dependent fast mutex implementation to be used by CMutex
  194. /// and CFastMutex only.
  195. struct SSystemFastMutex
  196. {
  197.     TSystemMutex m_Handle;      ///< Mutex handle
  198.     /// Initialization flag values.
  199.     enum EMagic {
  200.         eMutexUninitialized = 0,        ///< Uninitialized value.
  201.         eMutexInitialized = 0x2487adab  ///< Magic initialized value,
  202.     };
  203.     volatile EMagic m_Magic;    ///< Magic flag
  204.     /// Acquire mutex for the current thread with no nesting checks.
  205.     void Lock(void);
  206.     /// Release mutex with no owner or nesting checks.
  207.     void Unlock(void);
  208.     /// Try to lock.
  209.     /// 
  210.     /// @return
  211.     ///   TRUE on success; FALSE, otherwise.
  212.     bool TryLock(void);
  213.     /// Check initialized value of mutex.
  214.     void CheckInitialized(void) const;
  215.     // Methods for throwing exceptions, to make inlined methods lighter
  216.     /// Throw uninitialized ("eUninitialized") exception.
  217.     NCBI_XNCBI_EXPORT
  218.     static void ThrowUninitialized(void);
  219.     /// Throw lock failed("eLocked") exception.
  220.     NCBI_XNCBI_EXPORT
  221.     static void ThrowLockFailed(void);
  222.     /// Throw unlock failed("eUnlocked") exception.
  223.     NCBI_XNCBI_EXPORT
  224.     static void ThrowUnlockFailed(void);
  225.     /// Throw try lock failed("eTryLock") exception.
  226.     NCBI_XNCBI_EXPORT
  227.     static void ThrowTryLockFailed(void);
  228. #if !defined(NCBI_OS_MSWIN)
  229.     // MS VC 6 treats classes with any non-public member as non-POD.
  230. protected:
  231. #endif
  232.     /// Check if mutex is initialized.
  233.     /// 
  234.     /// @return
  235.     ///   TRUE if initialized; FALSE, otherwise.
  236.     bool IsInitialized(void) const;
  237.     /// Check if mutex is un-initialized.
  238.     /// 
  239.     /// @return
  240.     ///   TRUE if un-initialized; FALSE, otherwise.
  241.     bool IsUninitialized(void) const;
  242.     /// Initialize static mutex. 
  243.     ///
  244.     /// Must be called only once.
  245.     NCBI_XNCBI_EXPORT
  246.     void InitializeStatic(void);
  247.     /// Initialize dynamic mutex.
  248.     ///
  249.     /// Initialize mutex if it located in heap or stack. This must be called
  250.     /// only once.  Do not count on zeroed memory values for initializing
  251.     /// mutex values.
  252.     NCBI_XNCBI_EXPORT
  253.     void InitializeDynamic(void);
  254.     /// Destroy mutex.
  255.     NCBI_XNCBI_EXPORT
  256.     void Destroy(void);
  257.     /// Initialize mutex handle.
  258.     ///
  259.     /// Must be called only once.
  260.     NCBI_XNCBI_EXPORT
  261.     void InitializeHandle(void);
  262.     /// Destroy mutex handle.
  263.     ///
  264.     /// Must be called only once.
  265.     NCBI_XNCBI_EXPORT
  266.     void DestroyHandle(void);
  267.     friend struct SSystemMutex;
  268.     friend class CAutoInitializeStaticFastMutex;
  269.     friend class CFastMutex;
  270.     friend class CFastMutexGuard;
  271.     friend class CSafeStaticPtr_Base;
  272. };
  273. class CMutex;
  274. class CMutexGuard;
  275. /////////////////////////////////////////////////////////////////////////////
  276. ///
  277. /// SSystemMutex --
  278. ///
  279. /// Define system mutex.
  280. ///
  281. /// Internal platform-dependent mutex implementation to be used by CMutex
  282. /// and CFastMutex only.
  283. struct SSystemMutex
  284. {
  285.     SSystemFastMutex m_Mutex; ///< Mutex value
  286.     volatile CThreadSystemID m_Owner; ///< Platform-dependent owner thread ID
  287.     volatile int m_Count; ///< # of recursive (in the same thread) locks
  288.     /// Acquire mutex for the current thread.
  289.     NCBI_XNCBI_EXPORT
  290.     void Lock(void);
  291.     /// Release mutex.
  292.     NCBI_XNCBI_EXPORT
  293.     void Unlock(void);
  294.     /// Try to lock.
  295.     /// 
  296.     /// @return
  297.     ///   TRUE on success; FALSE, otherwise.
  298.     NCBI_XNCBI_EXPORT
  299.     bool TryLock(void);
  300.     // Methods for throwing exceptions, to make inlined methods lighter
  301.     // throw exception eOwner
  302.     /// Throw not owned("eOwner") exception.
  303.     NCBI_XNCBI_EXPORT
  304.     static void ThrowNotOwned(void);
  305. #if !defined(NCBI_OS_MSWIN)
  306. protected:
  307. #endif
  308.     /// Check if mutex is initialized.
  309.     /// 
  310.     /// @return
  311.     ///   TRUE if initialized; FALSE, otherwise.
  312.     bool IsInitialized(void) const;
  313.     /// Check if mutex is un-initialized.
  314.     /// 
  315.     /// @return
  316.     ///   TRUE if un-initialized; FALSE, otherwise.
  317.     bool IsUninitialized(void) const;
  318.     /// Initialize static mutex. 
  319.     ///
  320.     /// Must be called only once.
  321.     void InitializeStatic(void);
  322.     /// Initialize dynamic mutex.
  323.     ///
  324.     /// Initialize mutex if it located in heap or stack. This must be called
  325.     /// only once.  Do not count on zeroed memory values for initializing
  326.     /// mutex values.
  327.     void InitializeDynamic(void);
  328.     /// Destroy mutex.
  329.     NCBI_XNCBI_EXPORT
  330.     void Destroy(void);
  331.     friend class CAutoInitializeStaticMutex;
  332.     friend class CMutex;
  333.     friend class CMutexGuard;
  334. };
  335. /// Determine type of system mutex initialization.
  336. #if defined(SYSTEM_MUTEX_INITIALIZER)
  337. /// Define static fast mutex initial value.
  338. #   define STATIC_FAST_MUTEX_INITIALIZER 
  339.     { SYSTEM_MUTEX_INITIALIZER, NCBI_NS_NCBI::SSystemFastMutex::eMutexInitialized }
  340. /// Define static fast mutex and initialize it.
  341. #   define DEFINE_STATIC_FAST_MUTEX(id) 
  342. static NCBI_NS_NCBI::SSystemFastMutex id = STATIC_FAST_MUTEX_INITIALIZER
  343. /// Declare static fast mutex.
  344. #   define DECLARE_CLASS_STATIC_FAST_MUTEX(id) 
  345. static NCBI_NS_NCBI::SSystemFastMutex id
  346. /// Define fast mutex and initialize it.
  347. #   define DEFINE_CLASS_STATIC_FAST_MUTEX(id) 
  348. NCBI_NS_NCBI::SSystemFastMutex id = STATIC_FAST_MUTEX_INITIALIZER
  349. /// Define static mutex initializer.
  350. #   define STATIC_MUTEX_INITIALIZER 
  351.     { STATIC_FAST_MUTEX_INITIALIZER, THREAD_SYSTEM_ID_INITIALIZER, 0 }
  352. /// Define static mutex and initialize it.
  353. #   define DEFINE_STATIC_MUTEX(id) 
  354. static NCBI_NS_NCBI::SSystemMutex id = STATIC_MUTEX_INITIALIZER
  355. /// Declare static mutex.
  356. #   define DECLARE_CLASS_STATIC_MUTEX(id) 
  357. static NCBI_NS_NCBI::SSystemMutex id
  358. /// Define mutex and initialize it.
  359. #   define DEFINE_CLASS_STATIC_MUTEX(id) 
  360. NCBI_NS_NCBI::SSystemMutex id = STATIC_MUTEX_INITIALIZER
  361. #else
  362. /// Auto initialization for mutex will be used.
  363. #   define NEED_AUTO_INITIALIZE_MUTEX
  364. /// Define auto-initialized static fast mutex.
  365. #   define DEFINE_STATIC_FAST_MUTEX(id) 
  366. static NCBI_NS_NCBI::CAutoInitializeStaticFastMutex id
  367. /// Declare auto-initialized static fast mutex.
  368. #   define DECLARE_CLASS_STATIC_FAST_MUTEX(id) 
  369. static NCBI_NS_NCBI::CAutoInitializeStaticFastMutex id
  370. /// Define auto-initialized mutex.
  371. #   define DEFINE_CLASS_STATIC_FAST_MUTEX(id) 
  372. NCBI_NS_NCBI::CAutoInitializeStaticFastMutex id
  373. /// Define auto-initialized static mutex.
  374. #   define DEFINE_STATIC_MUTEX(id) 
  375. static NCBI_NS_NCBI::CAutoInitializeStaticMutex id
  376. /// Declare auto-initialized static mutex.
  377. #   define DECLARE_CLASS_STATIC_MUTEX(id) 
  378. static NCBI_NS_NCBI::CAutoInitializeStaticMutex id
  379. /// Define auto-initialized mutex.
  380. #   define DEFINE_CLASS_STATIC_MUTEX(id) 
  381. NCBI_NS_NCBI::CAutoInitializeStaticMutex id
  382. #endif
  383. #if defined(NEED_AUTO_INITIALIZE_MUTEX)
  384. /////////////////////////////////////////////////////////////////////////////
  385. ///
  386. /// CAutoInitializeStaticFastMutex --
  387. ///
  388. /// Define thread safe initializer static for SSystemFastMutex. 
  389. ///
  390. /// Needed on platforms where system mutex struct cannot be initialized at
  391. /// compile time (e.g. Win32).
  392. class CAutoInitializeStaticFastMutex
  393. {
  394. public:
  395.     typedef SSystemFastMutex TObject; ///< Simplified alias name for fast mutex
  396.     /// Lock mutex.
  397.     void Lock(void);
  398.     /// Unlock mutex.
  399.     void Unlock(void);
  400.     /// Try locking the mutex.
  401.     bool TryLock(void);
  402.     /// Return initialized mutex object.
  403.     operator TObject&(void);
  404. protected:
  405.     /// Initialize mutex.
  406.     ///
  407.     /// This method can be called many times it will return only after
  408.     /// successful initialization of m_Mutex.
  409.     NCBI_XNCBI_EXPORT
  410.     void Initialize(void);
  411.     /// Get initialized mutex object.
  412.     TObject& Get(void);
  413. private:
  414.     TObject m_Mutex;                ///< Mutex object.
  415. };
  416. /////////////////////////////////////////////////////////////////////////////
  417. ///
  418. /// CAutoInitializeStaticMutex --
  419. ///
  420. /// Define thread safe initializer static for SSystemMutex. 
  421. ///
  422. /// Needed on platforms where system mutex struct cannot be initialized at
  423. /// compile time (e.g. Win32).
  424. class CAutoInitializeStaticMutex
  425. {
  426. public:
  427.     typedef SSystemMutex TObject;   ///< Simplified alias name for fast mutex
  428.     /// Lock mutex.
  429.     void Lock(void);
  430.     /// Unlock mutex.
  431.     void Unlock(void);
  432.     /// Try locking the mutex.
  433.     bool TryLock(void);
  434.     /// Return initialized mutex object.
  435.     operator TObject&(void);
  436. protected:
  437.     /// Initialize mutex.
  438.     ///
  439.     /// This method can be called many times it will return only after
  440.     /// successful initialization of m_Mutex.
  441.     NCBI_XNCBI_EXPORT
  442.     void Initialize(void);
  443.     /// Get initialized mutex object.
  444.     TObject& Get(void);
  445. private:
  446.     TObject m_Mutex;                ///< Mutex object.
  447. };
  448. #endif
  449. /////////////////////////////////////////////////////////////////////////////
  450. //
  451. //  FAST MUTEX
  452. //
  453. //    CFastMutex::
  454. //    CFastMutexGuard::
  455. //
  456. /////////////////////////////////////////////////////////////////////////////
  457. ///
  458. /// CFastMutex --
  459. ///
  460. /// Simple mutex with fast lock/unlock functions.
  461. ///
  462. /// This mutex can be used instead of CMutex if it's guaranteed that
  463. /// there is no nesting. This mutex does not check nesting or owner.
  464. /// It has better performance than CMutex, but is less secure.
  465. class CFastMutex
  466. {
  467. public:
  468.     /// Constructor.
  469.     ///
  470.     /// Creates mutex handle.
  471.     CFastMutex(void);
  472.     /// Destructor.
  473.     ///
  474.     /// Close mutex handle. No checks if it's still acquired.
  475.     ~CFastMutex(void);
  476.     /// Define Read Lock Guard.
  477.     typedef CFastMutexGuard TReadLockGuard;
  478.     /// Define Write Lock Guard.
  479.     typedef CFastMutexGuard TWriteLockGuard;
  480.     /// Acquire mutex for the current thread with no nesting checks.
  481.     void Lock(void);
  482.     /// Release mutex with no owner or nesting checks.
  483.     void Unlock(void);
  484.     /// Try locking the mutex.
  485.     bool TryLock(void);
  486.     /// Get SSystemFastMutex.
  487.     operator SSystemFastMutex&(void);
  488. private:
  489. #if defined(NCBI_WIN32_THREADS)
  490.     /// Get handle - Windows version.
  491.     /// 
  492.     /// Also used by CRWLock.
  493.     HANDLE GetHandle(void) { return m_Mutex.m_Handle; }
  494. #else
  495.     /// Get handle - Unix version.
  496.     /// 
  497.     /// Also used by CRWLock.
  498.     TSystemMutex* GetHandle(void) { return &m_Mutex.m_Handle; }
  499. #endif
  500.     friend class CRWLock;
  501.     /// Platform-dependent mutex handle, also used by CRWLock.
  502.     SSystemFastMutex m_Mutex;
  503.     /// Private copy constructor to disallow initialization.
  504.     CFastMutex(const CFastMutex&);
  505.     /// Private assignment operator to disallow assignment.
  506.     CFastMutex& operator= (const CFastMutex&);
  507. };
  508. /////////////////////////////////////////////////////////////////////////////
  509. ///
  510. /// CFastMutexGuard --
  511. ///
  512. /// For acquiring fast mutex, then guaranting its release.
  513. class CFastMutexGuard
  514. {
  515. public:
  516.     /// Constructor.
  517.     CFastMutexGuard(void);
  518.     /// Constructor.
  519.     ///
  520.     /// Register the mutex "mtx", to be released by the guard destructor.
  521.     CFastMutexGuard(SSystemFastMutex& mtx);
  522.     /// Destructor.
  523.     ///
  524.     /// Release the mutex, if it was (and still is) successfully acquired.
  525.     ~CFastMutexGuard(void);
  526.     /// Release the mutex right now but do not release it in the guard
  527.     /// destructor.
  528.     void Release(void);
  529.     /// Guard the specified mutex.
  530.     ///
  531.     /// Lock on mutex "mtx" (if it's not guarded yet) and start guarding it.
  532.     /// NOTE: It never holds more than one lock on the guarded mutex!
  533.     void Guard(SSystemFastMutex& mtx);
  534. private:
  535.     SSystemFastMutex* m_Mutex;  ///< The mutex - is NULL if released.
  536.     /// Private copy constructor to disallow initialization.
  537.     CFastMutexGuard(const CFastMutexGuard&);
  538.     /// Private assignment operator to disallow assignment.
  539.     CFastMutexGuard& operator= (const CFastMutexGuard&);
  540. };
  541. /////////////////////////////////////////////////////////////////////////////
  542. //
  543. //  MUTEX
  544. //
  545. //    CMutex::
  546. //    CMutexGuard::
  547. //
  548. /////////////////////////////////////////////////////////////////////////////
  549. ///
  550. /// CMutex --
  551. ///
  552. /// Mutex that allows nesting with runtime checks.
  553. ///
  554. /// Allows for recursive locks by the same thread. Checks the mutex
  555. /// owner before unlocking. This mutex should be used when performance
  556. /// is less important than data protection. For faster performance see
  557. /// CFastMutex.
  558. ///
  559. /// @sa
  560. ///   http://www.ncbi.nlm.nih.gov/books/bv.fcgi?call=bv.View..ShowSection&rid=toolkit.section.threads#CMutex
  561. class CMutex
  562. {
  563. public:
  564.     /// Constructor.
  565.     CMutex(void);
  566.     /// Destructor.
  567.     ///
  568.     /// Report error if the mutex is locked.
  569.     ~CMutex(void);
  570.     /// Define Read Lock Guard.
  571.     typedef CMutexGuard TReadLockGuard;
  572.     /// Define Write Lock Guard.
  573.     typedef CMutexGuard TWriteLockGuard;
  574.     /// Get SSystemMutex.
  575.     operator SSystemMutex&(void);
  576.     /// Lock mutex.
  577.     ///
  578.     /// Operation:
  579.     /// - If the mutex is unlocked, then acquire it for the calling thread.
  580.     /// - If the mutex is acquired by this thread, then increase the
  581.     /// lock counter (each call to Lock() must have corresponding
  582.     /// call to Unlock() in the same thread).
  583.     /// - If the mutex is acquired by another thread, then wait until it's
  584.     /// unlocked, then act like a Lock() on an unlocked mutex.
  585.     void Lock(void);
  586.     /// Try locking mutex.
  587.     ///
  588.     /// Try to acquire the mutex.
  589.     /// @return
  590.     ///   - On success, return TRUE, and acquire the mutex just as the Lock() does.
  591.     ///   - If the mutex is already acquired by another thread, then return FALSE.
  592.     /// @sa
  593.     ///   Lock()
  594.     bool TryLock(void);
  595.     /// Unlock mutex.
  596.     ///
  597.     /// Operation:
  598.     /// - If the mutex is acquired by this thread, then decrease the lock counter.
  599.     /// - If the lock counter becomes zero, then release the mutex completely.
  600.     /// - Report error if the mutex is not locked or locked by another thread.
  601.     void Unlock(void);
  602. private:
  603.     SSystemMutex m_Mutex;    ///< System mutex
  604.     /// Private copy constructor to disallow initialization.
  605.     CMutex(const CMutex&);
  606.     /// Private assignment operator to disallow assignment.
  607.     CMutex& operator= (const CMutex&);
  608.     friend class CRWLock; ///< Allow use of m_Mtx and m_Owner members directly
  609. };
  610. /////////////////////////////////////////////////////////////////////////////
  611. ///
  612. /// CMutexGuard --
  613. ///
  614. /// Guarded mutex.
  615. ///
  616. /// Acquires the mutex and then gurantees its release.
  617. class CMutexGuard
  618. {
  619. public:
  620.     /// Constructor.
  621.     CMutexGuard(void);
  622.     /// Constructor.
  623.     ///
  624.     /// Acquire the mutex "mtx"; register it to be released by the guard
  625.     /// destructor.
  626.     CMutexGuard(SSystemMutex& mtx);
  627.     /// Destructor.
  628.     ///
  629.     /// Release the mutex, if it was (and still is) successfully acquired.
  630.     ~CMutexGuard(void);
  631.     /// Release mutex.
  632.     ///
  633.     /// Release the mutex right now -- do not release it in the guard
  634.     /// destructor.
  635.     void Release(void);
  636.     /// Guard mutex.
  637.     ///
  638.     /// Lock on mutex "mtx" (if it's not guarded yet) and start guarding it.
  639.     /// NOTE: it never holds more than one lock on the guarded mutex!
  640.     void Guard(SSystemMutex& mtx);
  641. private:
  642.     SSystemMutex* m_Mutex;  ///< The mutex -- NULL if released.
  643.     /// Private copy constructor to disallow initialization.
  644.     CMutexGuard(const CMutexGuard&);
  645.     /// Private assignment operator to disallow assignment.
  646.     CMutexGuard& operator= (const CMutexGuard&);
  647. };
  648. /////////////////////////////////////////////////////////////////////////////
  649. //
  650. //  RW-LOCK
  651. //
  652. //    CRWLock::
  653. //    CAutoRW::
  654. //    CReadLockGuard::
  655. //    CWriteLockGuard::
  656. //
  657. // Forward declaration of internal (platform-dependent) RW-lock representation
  658. class CInternalRWLock;
  659. class CReadLockGuard;
  660. class CWriteLockGuard;
  661. /////////////////////////////////////////////////////////////////////////////
  662. ///
  663. /// CRWLock --
  664. ///
  665. /// Read/Write lock related data and methods.
  666. ///
  667. /// Allows multiple readers or single writer with recursive locks.
  668. /// R-after-W is considered to be a recursive Write-lock. W-after-R is not
  669. /// allowed.
  670. ///
  671. /// NOTE: When _DEBUG is not defined, does not always detect W-after-R
  672. /// correctly, so that deadlock may happen. Test your application
  673. /// in _DEBUG mode first!
  674. class NCBI_XNCBI_EXPORT CRWLock
  675. {
  676. public:
  677.     /// Constructor.
  678.     CRWLock(void);
  679.     /// Destructor.
  680.     ~CRWLock(void);
  681.     /// Define Read Lock Guard.
  682.     typedef CReadLockGuard TReadLockGuard;
  683.     /// Define Write Lock Guard.
  684.     typedef CWriteLockGuard TWriteLockGuard;
  685.     /// Read lock.
  686.     ///
  687.     /// Acquire the R-lock. If W-lock is already acquired by
  688.     /// another thread, then wait until it is released.
  689.     void ReadLock(void);
  690.     /// Write lock.
  691.     ///
  692.     /// Acquire the W-lock. If R-lock or W-lock is already acquired by
  693.     /// another thread, then wait until it is released.
  694.     void WriteLock(void);
  695.     /// Try read lock.
  696.     ///
  697.     /// Try to acquire R-lock and return immediately.
  698.     /// @return
  699.     ///   TRUE if the R-lock has been successfully acquired;
  700.     ///   FALSE, otherwise.
  701.     bool TryReadLock(void);
  702.     /// Try write lock.
  703.     ///
  704.     /// Try to acquire W-lock and return immediately.
  705.     /// @return
  706.     ///   TRUE if the W-lock has been successfully acquired;
  707.     ///   FALSE, otherwise.
  708.     bool TryWriteLock(void);
  709.     /// Release the RW-lock.
  710.     void Unlock(void);
  711. private:
  712.     
  713.     auto_ptr<CInternalRWLock>  m_RW;    ///< Platform-dependent RW-lock data
  714.     
  715.     volatile CThreadSystemID   m_Owner; ///< Writer ID, one of the readers ID
  716.     
  717.     volatile int               m_Count; ///< Number of readers (if >0) or
  718.                                         ///< writers (if <0)
  719.     
  720.     vector<CThreadSystemID>    m_Readers;   ///< List of all readers or writers
  721.                                             ///< for debugging
  722.     
  723.     /// Private copy constructor to disallow initialization.
  724.     CRWLock(const CRWLock&);
  725.                            
  726.     /// Private assignment operator to disallow assignment.
  727.     CRWLock& operator= (const CRWLock&);
  728. };
  729. /////////////////////////////////////////////////////////////////////////////
  730. ///
  731. /// CAutoRW --
  732. ///
  733. /// Guarantee RW-lock release.
  734. ///
  735. /// Acts in a way like "auto_ptr<>": guarantees RW-Lock release.
  736. class CAutoRW
  737. {
  738. public:
  739.     /// Constructor.
  740.     ///
  741.     /// Register the RW-lock to be released by the guard destructor.
  742.     /// Do NOT acquire the RW-lock though!
  743.     CAutoRW(void) : m_RW(0)
  744.         {
  745.         }
  746.     /// Destructor.
  747.     ///
  748.     /// Release the R-lock, if it was successfully acquired and
  749.     /// not released already by Release().
  750.     ~CAutoRW(void)
  751.         {
  752.             Release();
  753.         }
  754.     /// Release the RW-lock right now - don't release it in the guard
  755.     /// destructor.
  756.     void Release(void)
  757.         {
  758.             if ( m_RW ) {
  759.                 m_RW->Unlock();
  760.                 m_RW = 0;
  761.             }
  762.         }
  763. protected:
  764.     /// Get the RW-lock being guarded.
  765.     CRWLock* GetRW(void) const { return m_RW; }
  766.     CRWLock* m_RW;  /// The RW-lock -- NULL if not acquired.
  767.     /// Private copy constructor to disallow initialization.
  768.     CAutoRW(const CAutoRW&);
  769.     /// Private assignment operator to disallow assignment.
  770.     CAutoRW& operator= (const CAutoRW&);
  771. };
  772. /////////////////////////////////////////////////////////////////////////////
  773. ///
  774. /// CReadLockGuard --
  775. ///
  776. /// Acquire the R-lock, then guarantee for its release.
  777. class CReadLockGuard : public CAutoRW
  778. {
  779. public:
  780.     /// Constructor.
  781.     ///
  782.     /// Default constructor - do nothing.
  783.     CReadLockGuard(void)
  784.         {
  785.         }
  786.     /// Constructor.
  787.     ///
  788.     /// Acquire the R-lock;  register it to be released by the guard
  789.     /// destructor.
  790.     CReadLockGuard(CRWLock& rw)
  791.         {
  792.             rw.ReadLock();
  793.             m_RW = &rw;
  794.         }
  795.     void Guard(CRWLock& rw)
  796.         {
  797.             if ( &rw != m_RW ) {
  798.                 Release();
  799.                 rw.ReadLock();
  800.                 m_RW = &rw;
  801.             }
  802.         }
  803. private:
  804.     /// Private copy constructor to disallow initialization.
  805.     CReadLockGuard(const CReadLockGuard&);
  806.     /// Private assignment operator to disallow assignment.
  807.     CReadLockGuard& operator= (const CReadLockGuard&);
  808. };
  809. /////////////////////////////////////////////////////////////////////////////
  810. ///
  811. /// CWriteLockGuard --
  812. ///
  813. /// Acquire the W-lock, then guarantee for its release.
  814. class CWriteLockGuard : public CAutoRW
  815. {
  816. public:
  817.     /// Constructor.
  818.     ///
  819.     /// Default constructor - do nothing.
  820.     CWriteLockGuard(void)
  821.         {
  822.         }
  823.     /// Constructor.
  824.     ///
  825.     /// Acquire the W-lock;  register it to be released by the guard
  826.     /// destructor.
  827.     CWriteLockGuard(CRWLock& rw)
  828.         {
  829.             rw.WriteLock();
  830.             m_RW = &rw;
  831.         }
  832.     void Guard(CRWLock& rw)
  833.         {
  834.             if ( &rw != m_RW ) {
  835.                 Release();
  836.                 rw.WriteLock();
  837.                 m_RW = &rw;
  838.             }
  839.         }
  840. private:
  841.     /// Private copy constructor to disallow initialization.
  842.     CWriteLockGuard(const CWriteLockGuard&);
  843.     /// Private assignment operator to disallow assignment.
  844.     CWriteLockGuard& operator= (const CWriteLockGuard&);
  845. };
  846. /////////////////////////////////////////////////////////////////////////////
  847. ///
  848. /// CSemaphore --
  849. ///
  850. /// Implement the semantics of an application-wide semaphore.
  851. class NCBI_XNCBI_EXPORT CSemaphore
  852. {
  853. public:
  854.     /// Constructor.
  855.     ///
  856.     /// @param
  857.     ///   int_count   The initial value of the semaphore.
  858.     ///   max_count   Maximum value that semaphore value can be incremented to.
  859.     CSemaphore(unsigned int init_count, unsigned int max_count);
  860.     /// Destructor.
  861.     ///
  862.     /// Report error if the semaphore is locked.
  863.     ~CSemaphore(void);
  864.     /// Wait on semaphore.
  865.     ///
  866.     /// Decrement the counter by one. If the semaphore's count is zero then
  867.     /// wait until it's not zero.
  868.     void Wait(void);
  869.     /// Timed wait.
  870.     ///
  871.     /// Wait up to timeout_sec + timeout_nsec/1E9 seconds for the
  872.     /// semaphore's count to exceed zero.  If that happens, decrement
  873.     /// the counter by one and return TRUE; otherwise, return FALSE.
  874.     bool TryWait(unsigned int timeout_sec = 0, unsigned int timeout_nsec = 0);
  875.     /// Increment the semaphore by "count".
  876.     ///
  877.     /// Do nothing and throw an exception if counter would exceed "max_count".
  878.     void Post(unsigned int count = 1);
  879. private:
  880.     struct SSemaphore* m_Sem;  ///< System-specific semaphore data.
  881.     /// Private copy constructor to disallow initialization.
  882.     CSemaphore(const CSemaphore&);
  883.     /// Private assignment operator to disallow assignment.
  884.     CSemaphore& operator= (const CSemaphore&);
  885. };
  886. /* @} */
  887. #include <corelib/ncbimtx.inl>
  888. /////////////////////////////////////////////////////////////////////////////
  889. END_NCBI_SCOPE
  890. /*
  891.  * ===========================================================================
  892.  * $Log: ncbimtx.hpp,v $
  893.  * Revision 1000.2  2004/04/21 14:34:52  gouriano
  894.  * PRODUCTION: UPGRADED [CATCHUP_003] Dev-tree R1.35
  895.  *
  896.  * Revision 1.35  2004/03/10 20:00:24  gorelenk
  897.  * Added NCBI_XNCBI_EXPORT prefix to SSystemMutex struct members Lock, Unlock,
  898.  * Trylock.
  899.  *
  900.  * Revision 1.34  2004/03/10 18:40:21  gorelenk
  901.  * Added/Removed NCBI_XNCBI_EXPORT prefixes.
  902.  *
  903.  * Revision 1.33  2004/03/10 17:34:05  gorelenk
  904.  * Removed NCBI_XNCBI_EXPORT prefix for classes members-functions
  905.  * that are implemented as a inline functions.
  906.  *
  907.  * Revision 1.32  2003/10/30 14:56:27  siyan
  908.  * Added a test for @sa hyperlink.
  909.  *
  910.  * Revision 1.31  2003/09/30 16:07:39  vasilche
  911.  * Allow release and reacqure rw lock in guard.
  912.  *
  913.  * Revision 1.30  2003/09/29 20:50:30  ivanov
  914.  * Removed CAutoInitializeStaticBase
  915.  *
  916.  * Revision 1.29  2003/09/17 18:09:05  vasilche
  917.  * Removed unnecessary assignment operator - it causes problems on MSVC.
  918.  *
  919.  * Revision 1.28  2003/09/17 17:56:46  vasilche
  920.  * Fixed volatile methods of CThreadSystemID.
  921.  *
  922.  * Revision 1.27  2003/09/17 15:20:45  vasilche
  923.  * Moved atomic counter swap functions to separate file.
  924.  * Added CRef<>::AtomicResetFrom(), CRef<>::AtomicReleaseTo() methods.
  925.  *
  926.  * Revision 1.26  2003/09/02 16:36:50  vasilche
  927.  * Fixed warning on MSVC.
  928.  *
  929.  * Revision 1.25  2003/09/02 16:08:48  vasilche
  930.  * Fixed race condition with optimization on some compilers - added 'volatile'.
  931.  * Moved mutex Lock/Unlock methods out of inline section - they are quite complex.
  932.  *
  933.  * Revision 1.24  2003/09/02 15:06:14  siyan
  934.  * Minor comment changes.
  935.  *
  936.  * Revision 1.23  2003/08/27 12:35:15  siyan
  937.  * Added documentation.
  938.  *
  939.  * Revision 1.22  2003/06/19 18:21:15  vasilche
  940.  * Added default constructors to CFastMutexGuard and CMutexGuard.
  941.  * Added typedefs TReadLockGuard and TWriteLockGuard to mutexes and rwlock.
  942.  *
  943.  * Revision 1.21  2003/03/31 13:30:31  siyan
  944.  * Minor changes to doxygen support
  945.  *
  946.  * Revision 1.20  2003/03/31 13:09:19  siyan
  947.  * Added doxygen support
  948.  *
  949.  * Revision 1.19  2002/12/18 22:53:21  dicuccio
  950.  * Added export specifier for building DLLs in windows.  Added global list of
  951.  * all such specifiers in mswin_exports.hpp, included through ncbistl.hpp
  952.  *
  953.  * Revision 1.18  2002/09/23 13:58:29  vasilche
  954.  * MS VC 6 doesn't accept empty initialization block
  955.  *
  956.  * Revision 1.17  2002/09/23 13:47:23  vasilche
  957.  * Made static mutex structures POD-types on Win32
  958.  *
  959.  * Revision 1.16  2002/09/20 20:02:07  vasilche
  960.  * Added public Lock/Unlock/TryLock
  961.  *
  962.  * Revision 1.15  2002/09/20 19:28:21  vasilche
  963.  * Fixed missing initialization with NCBI_NO_THREADS
  964.  *
  965.  * Revision 1.14  2002/09/20 19:13:58  vasilche
  966.  * Fixed single-threaded mode on Win32
  967.  *
  968.  * Revision 1.13  2002/09/20 13:51:56  vasilche
  969.  * Added #include <memory> for auto_ptr<>
  970.  *
  971.  * Revision 1.12  2002/09/19 20:05:41  vasilche
  972.  * Safe initialization of static mutexes
  973.  *
  974.  * Revision 1.11  2002/08/19 19:37:17  vakatov
  975.  * Use <corelib/ncbi_os_mswin.hpp> in the place of <windows.h>
  976.  *
  977.  * Revision 1.10  2002/08/19 18:15:58  ivanov
  978.  * +include <corelib/winundef.hpp>
  979.  *
  980.  * Revision 1.9  2002/07/15 18:17:51  gouriano
  981.  * renamed CNcbiException and its descendents
  982.  *
  983.  * Revision 1.8  2002/07/11 14:17:54  gouriano
  984.  * exceptions replaced by CNcbiException-type ones
  985.  *
  986.  * Revision 1.7  2002/04/11 20:39:18  ivanov
  987.  * CVS log moved to end of the file
  988.  *
  989.  * Revision 1.6  2002/01/23 23:31:17  vakatov
  990.  * Added CFastMutexGuard::Guard()
  991.  *
  992.  * Revision 1.5  2001/05/17 14:53:50  lavr
  993.  * Typos corrected
  994.  *
  995.  * Revision 1.4  2001/04/16 18:45:28  vakatov
  996.  * Do not include system MT-related headers if in single-thread mode
  997.  *
  998.  * Revision 1.3  2001/03/26 22:50:24  grichenk
  999.  * Fixed CFastMutex::Unlock() bug
  1000.  *
  1001.  * Revision 1.2  2001/03/26 21:11:37  vakatov
  1002.  * Allow use of not yet initialized mutexes (with A.Grichenko)
  1003.  *
  1004.  * Revision 1.1  2001/03/13 22:34:24  vakatov
  1005.  * Initial revision
  1006.  *
  1007.  * ===========================================================================
  1008.  */
  1009. #endif  /* NCBIMTX__HPP */