include/corelib/ncbimtx.hpp

Go to the documentation of this file.
00001 #ifndef CORELIB___NCBIMTX__HPP
00002 #define CORELIB___NCBIMTX__HPP
00003 
00004 /*  $Id: ncbimtx.hpp 173634 2009-10-20 13:02:43Z ivanovp $
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  * Author:  Denis Vakatov, Aleksey Grichenko
00030  *
00031  *
00032  */
00033 
00034 /// @file ncbimtx.hpp
00035 /// Multi-threading -- mutexes;  rw-locks; semaphore
00036 ///
00037 ///   MUTEX:
00038 ///
00039 /// MUTEX CLASSES:
00040 /// - SSystemFastMutex -- platform-dependent mutex functionality
00041 /// - SSystemMutex     -- platform-dependent mutex functionality
00042 /// - CFastMutex       -- simple mutex with fast lock/unlock functions
00043 /// - CMutex           -- mutex that allows nesting (with runtime checks)
00044 /// - CFastMutexGuard  -- acquire fast mutex, then guarantee for its release
00045 /// - CMutexGuard      -- acquire mutex, then guarantee for its release
00046 ///
00047 /// RW-LOCK:
00048 /// - CInternalRWLock  -- platform-dependent RW-lock structure (fwd-decl)
00049 /// - CRWLock          -- Read/Write lock related  data and methods
00050 /// - CAutoRW          -- guarantee RW-lock release
00051 /// - CReadLockGuard   -- acquire R-lock, then guarantee for its release
00052 /// - CWriteLockGuard  -- acquire W-lock, then guarantee for its release
00053 ///
00054 /// SEMAPHORE:
00055 /// - CSemaphore       -- application-wide semaphore
00056 ///
00057 
00058 
00059 #include <corelib/ncbithr_conf.hpp>
00060 #include <corelib/ncbicntr.hpp>
00061 #include <corelib/guard.hpp>
00062 #include <corelib/ncbiobj.hpp>
00063 #include <memory>
00064 #include <deque>
00065 
00066 
00067 /** @addtogroup Threads
00068  *
00069  * @{
00070  */
00071 
00072 
00073 #if defined(_DEBUG)
00074 /// Mutex debug setting.
00075 #   define  INTERNAL_MUTEX_DEBUG
00076 #else
00077 #   undef   INTERNAL_MUTEX_DEBUG
00078 /// Mutex debug setting.
00079 #   define  INTERNAL_MUTEX_DEBUG
00080 #endif
00081 
00082 
00083 BEGIN_NCBI_SCOPE
00084 
00085 
00086 /////////////////////////////////////////////////////////////////////////////
00087 //
00088 // Log mutex events if LOG_MUTEX_EVENTS is defined.
00089 //
00090 //    The mutex events (create/destroy/lock/unlock) are logged into
00091 //    ./mutex_events.log or the one specified in MUTEX_EVENTS_LOG_FILE
00092 //    env. variable.
00093 //
00094 
00095 #if defined(_DEBUG) &&  defined(LOG_MUTEX_EVENTS)
00096 
00097 // Logging function, prints pointer to the mutex, system thread ID
00098 // and the message.
00099  void WriteMutexEvent(void* mutex_ptr, const char* message);
00100 #  define WRITE_MUTEX_EVENT(mutex, message) WriteMutexEvent(mutex, message)
00101 
00102 #else
00103 
00104 #  define WRITE_MUTEX_EVENT(mutex, message) ((void)0)
00105 
00106 #endif
00107 
00108 
00109 /////////////////////////////////////////////////////////////////////////////
00110 //
00111 // DECLARATIONS of internal (platform-dependent) representations
00112 //
00113 //    TMutex         -- internal mutex type
00114 //
00115 
00116 #if defined(NCBI_NO_THREADS)
00117 
00118 /// Define a platform independent system mutex.
00119 typedef int TSystemMutex; // fake
00120 # define SYSTEM_MUTEX_INITIALIZER 0
00121 
00122 #elif defined(NCBI_POSIX_THREADS)
00123 
00124 /// Define a platform independent system mutex.
00125 typedef pthread_mutex_t TSystemMutex;
00126 # define SYSTEM_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
00127 
00128 #elif defined(NCBI_WIN32_THREADS)
00129 
00130 #  define NCBI_USE_CRITICAL_SECTION
00131 
00132 /// Define a platform independent system mutex.
00133 #  if defined(NCBI_USE_CRITICAL_SECTION)
00134 typedef CRITICAL_SECTION TSystemMutex;
00135 #  else
00136 typedef HANDLE TSystemMutex;
00137 #  endif
00138 
00139 # undef SYSTEM_MUTEX_INITIALIZER
00140 
00141 #else
00142 #  error Unknown threads type
00143 #endif
00144 
00145 
00146 
00147 /////////////////////////////////////////////////////////////////////////////
00148 ///
00149 /// CThreadSystemID --
00150 ///
00151 /// Define thread system ID.
00152 ///
00153 /// The CThreadSystemID is based on the platform dependent thread ID type,
00154 /// TThreadSystemID, defined in ncbithr_conf.hpp.
00155 
00156 class  CThreadSystemID
00157 {
00158 public:
00159     /// Define a simpler alias for TThreadSystemID.
00160     typedef TThreadSystemID TID;
00161 
00162     TID m_ID;           ///< Thread ID.
00163 
00164     /// Get the current thread ID.
00165     static CThreadSystemID GetCurrent(void)
00166         {
00167             CThreadSystemID id;
00168 #if defined(NCBI_NO_THREADS)
00169             id.m_ID = TID(0);
00170 #elif defined(NCBI_POSIX_THREADS)
00171             id.m_ID = pthread_self();
00172 #elif defined(NCBI_WIN32_THREADS)
00173             id.m_ID = GetCurrentThreadId();
00174 #endif
00175             return id;
00176         }
00177 
00178     /// Equality operator for thread ID.
00179     bool operator==(const CThreadSystemID& id) const
00180         {
00181             return m_ID == id.m_ID;
00182         }
00183 
00184     /// Non-equality operator for thread ID.
00185     bool operator!=(const CThreadSystemID& id) const
00186         {
00187             return m_ID != id.m_ID;
00188         }
00189 
00190     /// volatile versions of above methods
00191     void Set(const CThreadSystemID& id) volatile
00192         {
00193             m_ID = id.m_ID;
00194         }
00195     bool Is(const CThreadSystemID& id) const volatile
00196         {
00197             return m_ID == id.m_ID;
00198         }
00199     bool IsNot(const CThreadSystemID& id) const volatile
00200         {
00201             return m_ID != id.m_ID;
00202         }
00203 };
00204 
00205 
00206 /// Use in defining initial value of system mutex.
00207 #define THREAD_SYSTEM_ID_INITIALIZER { 0 }
00208 
00209 
00210 
00211 /////////////////////////////////////////////////////////////////////////////
00212 ///
00213 /// CMutexException --
00214 ///
00215 /// Define exceptions generated by mutexes.
00216 ///
00217 /// CMutexException inherits its basic functionality from CCoreException
00218 /// and defines additional error codes for applications.
00219 
00220 class  CMutexException : public CCoreException
00221 {
00222 public:
00223     /// Error types that a mutex can generate.
00224     enum EErrCode {
00225         eLock,          ///< Lock error
00226         eUnlock,        ///< Unlock error
00227         eTryLock,       ///< Attempted lock error
00228         eOwner,         ///< Not owned error
00229         eUninitialized  ///< Uninitialized error
00230     };
00231 
00232     /// Translate from the error code value to its string representation.
00233     virtual const char* GetErrCodeString(void) const;
00234 
00235     // Standard exception boilerplate code.
00236     NCBI_EXCEPTION_DEFAULT(CMutexException,CCoreException);
00237 };
00238 
00239 /////////////////////////////////////////////////////////////////////////////
00240 //
00241 //  SYSTEM MUTEX
00242 //
00243 //    SSystemFastMutex
00244 //    SSystemMutex
00245 //
00246 
00247 class CFastMutex;
00248 
00249 
00250 
00251 /////////////////////////////////////////////////////////////////////////////
00252 ///
00253 /// SSystemFastMutex --
00254 ///
00255 /// Define system fast mutex.
00256 ///
00257 /// Internal platform-dependent fast mutex implementation to be used by CMutex
00258 /// and CFastMutex only.
00259 
00260 struct SSystemFastMutex
00261 {
00262     TSystemMutex m_Handle;      ///< Mutex handle
00263 
00264     /// Initialization flag values.
00265     enum EMagic {
00266         eMutexUninitialized = 0,        ///< Uninitialized value.
00267         eMutexInitialized = 0x2487adab  ///< Magic initialized value,
00268     };
00269     volatile EMagic m_Magic;    ///< Magic flag
00270 
00271     /// Acquire mutex for the current thread with no nesting checks.
00272     
00273     void Lock(void);
00274 
00275     /// Release mutex with no owner or nesting checks.
00276     
00277     void Unlock(void);
00278 
00279     /// Try to lock.
00280     /// 
00281     /// @return
00282     ///   TRUE on success; FALSE, otherwise.
00283     
00284     bool TryLock(void);
00285 
00286     /// Check initialized value of mutex.
00287     void CheckInitialized(void) const;
00288 
00289     // Methods for throwing exceptions, to make inlined methods lighter
00290 
00291     /// Throw uninitialized ("eUninitialized") exception.
00292     
00293     static void ThrowUninitialized(void);
00294 
00295     /// Throw lock failed("eLocked") exception.
00296     
00297     static void ThrowLockFailed(void);
00298 
00299     /// Throw unlock failed("eUnlocked") exception.
00300     
00301     static void ThrowUnlockFailed(void);
00302 
00303     /// Throw try lock failed("eTryLock") exception.
00304     
00305     static void ThrowTryLockFailed(void);
00306 
00307 #if !defined(NCBI_OS_MSWIN)
00308     // MS VC 6 treats classes with any non-public member as non-POD.
00309 protected:
00310 #endif
00311 
00312     /// Check if mutex is initialized.
00313     /// 
00314     /// @return
00315     ///   TRUE if initialized; FALSE, otherwise.
00316     bool IsInitialized(void) const;
00317 
00318     /// Check if mutex is un-initialized.
00319     /// 
00320     /// @return
00321     ///   TRUE if un-initialized; FALSE, otherwise.
00322     bool IsUninitialized(void) const;
00323 
00324     /// Initialize static mutex. 
00325     ///
00326     /// Must be called only once.
00327     
00328     void InitializeStatic(void);
00329 
00330     /// Initialize dynamic mutex.
00331     ///
00332     /// Initialize mutex if it located in heap or stack. This must be called
00333     /// only once.  Do not count on zeroed memory values for initializing
00334     /// mutex values.
00335     
00336     void InitializeDynamic(void);
00337 
00338     /// Destroy mutex.
00339     
00340     void Destroy(void);
00341 
00342     /// Initialize mutex handle.
00343     ///
00344     /// Must be called only once.
00345     
00346     void InitializeHandle(void);
00347 
00348     /// Destroy mutex handle.
00349     ///
00350     /// Must be called only once.
00351     
00352     void DestroyHandle(void);
00353 
00354     friend struct SSystemMutex;
00355     friend class CAutoInitializeStaticFastMutex;
00356 
00357     friend class CFastMutex;
00358 
00359     friend class CSafeStaticPtr_Base;
00360 };
00361 
00362 /// typedefs for ease of use
00363 typedef CGuard<SSystemFastMutex> TFastMutexGuard;
00364 
00365 /// ...and backward compatibility
00366 typedef TFastMutexGuard          CFastMutexGuard;
00367 
00368 
00369 class CMutex;
00370 
00371 
00372 
00373 /////////////////////////////////////////////////////////////////////////////
00374 ///
00375 /// SSystemMutex --
00376 ///
00377 /// Define system mutex.
00378 ///
00379 /// Internal platform-dependent mutex implementation to be used by CMutex
00380 /// and CFastMutex only.
00381 
00382 struct SSystemMutex
00383 {
00384     SSystemFastMutex m_Mutex; ///< Mutex value
00385 
00386     volatile CThreadSystemID m_Owner; ///< Platform-dependent owner thread ID
00387 
00388     volatile int m_Count; ///< # of recursive (in the same thread) locks
00389 
00390     /// Acquire mutex for the current thread.
00391     
00392     void Lock(void);
00393 
00394     /// Release mutex.
00395     
00396     void Unlock(void);
00397 
00398     /// Try to lock.
00399     /// 
00400     /// @return
00401     ///   TRUE on success; FALSE, otherwise.
00402     
00403     bool TryLock(void);
00404 
00405     // Methods for throwing exceptions, to make inlined methods lighter
00406     // throw exception eOwner
00407 
00408     /// Throw not owned("eOwner") exception.
00409     
00410     static void ThrowNotOwned(void);
00411 
00412 #if !defined(NCBI_OS_MSWIN)
00413 protected:
00414 #endif
00415     /// Check if mutex is initialized.
00416     /// 
00417     /// @return
00418     ///   TRUE if initialized; FALSE, otherwise.
00419     bool IsInitialized(void) const;
00420 
00421     /// Check if mutex is un-initialized.
00422     /// 
00423     /// @return
00424     ///   TRUE if un-initialized; FALSE, otherwise.
00425     bool IsUninitialized(void) const;
00426 
00427     /// Initialize static mutex. 
00428     ///
00429     /// Must be called only once.
00430     void InitializeStatic(void);
00431 
00432     /// Initialize dynamic mutex.
00433     ///
00434     /// Initialize mutex if it located in heap or stack. This must be called
00435     /// only once.  Do not count on zeroed memory values for initializing
00436     /// mutex values.
00437     void InitializeDynamic(void);
00438 
00439     /// Destroy mutex.
00440     
00441     void Destroy(void);
00442 
00443     friend class CAutoInitializeStaticMutex;
00444     friend class CMutex;
00445 };
00446 
00447 
00448 /// typedefs for ease of use
00449 typedef CGuard<SSystemMutex> TMutexGuard;
00450 
00451 /// ...and backward compatibility
00452 typedef TMutexGuard          CMutexGuard;
00453 
00454 
00455 /// Determine type of system mutex initialization.
00456 #if defined(SYSTEM_MUTEX_INITIALIZER)
00457 
00458 /// Define static fast mutex initial value.
00459 #   define STATIC_FAST_MUTEX_INITIALIZER \
00460     { SYSTEM_MUTEX_INITIALIZER, NCBI_NS_NCBI::SSystemFastMutex::eMutexInitialized }
00461 
00462 /// Define static fast mutex and initialize it.
00463 #   define DEFINE_STATIC_FAST_MUTEX(id) \
00464 static NCBI_NS_NCBI::SSystemFastMutex id = STATIC_FAST_MUTEX_INITIALIZER
00465 
00466 /// Declare static fast mutex.
00467 #   define DECLARE_CLASS_STATIC_FAST_MUTEX(id) \
00468 static NCBI_NS_NCBI::SSystemFastMutex id
00469 
00470 /// Define fast mutex and initialize it.
00471 #   define DEFINE_CLASS_STATIC_FAST_MUTEX(id) \
00472 NCBI_NS_NCBI::SSystemFastMutex id = STATIC_FAST_MUTEX_INITIALIZER
00473 
00474 /// Define static mutex initializer.
00475 #   define STATIC_MUTEX_INITIALIZER \
00476     { STATIC_FAST_MUTEX_INITIALIZER, THREAD_SYSTEM_ID_INITIALIZER, 0 }
00477 
00478 /// Define static mutex and initialize it.
00479 #   define DEFINE_STATIC_MUTEX(id) \
00480 static NCBI_NS_NCBI::SSystemMutex id = STATIC_MUTEX_INITIALIZER
00481 
00482 /// Declare static mutex.
00483 #   define DECLARE_CLASS_STATIC_MUTEX(id) \
00484 static NCBI_NS_NCBI::SSystemMutex id
00485 
00486 /// Define mutex and initialize it.
00487 #   define DEFINE_CLASS_STATIC_MUTEX(id) \
00488 NCBI_NS_NCBI::SSystemMutex id = STATIC_MUTEX_INITIALIZER
00489 
00490 #else
00491 
00492 /// Auto initialization for mutex will be used.
00493 #   define NEED_AUTO_INITIALIZE_MUTEX
00494 
00495 /// Define auto-initialized static fast mutex.
00496 #   define DEFINE_STATIC_FAST_MUTEX(id) \
00497 static NCBI_NS_NCBI::CAutoInitializeStaticFastMutex id
00498 
00499 /// Declare auto-initialized static fast mutex.
00500 #   define DECLARE_CLASS_STATIC_FAST_MUTEX(id) \
00501 static NCBI_NS_NCBI::CAutoInitializeStaticFastMutex id
00502 
00503 /// Define auto-initialized mutex.
00504 #   define DEFINE_CLASS_STATIC_FAST_MUTEX(id) \
00505 NCBI_NS_NCBI::CAutoInitializeStaticFastMutex id
00506 
00507 /// Define auto-initialized static mutex.
00508 #   define DEFINE_STATIC_MUTEX(id) \
00509 static NCBI_NS_NCBI::CAutoInitializeStaticMutex id
00510 
00511 /// Declare auto-initialized static mutex.
00512 #   define DECLARE_CLASS_STATIC_MUTEX(id) \
00513 static NCBI_NS_NCBI::CAutoInitializeStaticMutex id
00514 
00515 /// Define auto-initialized mutex.
00516 #   define DEFINE_CLASS_STATIC_MUTEX(id) \
00517 NCBI_NS_NCBI::CAutoInitializeStaticMutex id
00518 
00519 #endif
00520 
00521 
00522 
00523 #if defined(NEED_AUTO_INITIALIZE_MUTEX)
00524 
00525 
00526 
00527 /////////////////////////////////////////////////////////////////////////////
00528 ///
00529 /// CAutoInitializeStaticFastMutex --
00530 ///
00531 /// Define thread safe initializer static for SSystemFastMutex. 
00532 ///
00533 /// Needed on platforms where system mutex struct cannot be initialized at
00534 /// compile time (e.g. Win32).
00535 
00536 class CAutoInitializeStaticFastMutex
00537 {
00538 public:
00539     typedef SSystemFastMutex TObject; ///< Simplified alias name for fast mutex
00540 
00541     /// Lock mutex.
00542     void Lock(void);
00543 
00544     /// Unlock mutex.
00545     void Unlock(void);
00546 
00547     /// Try locking the mutex.
00548     bool TryLock(void);
00549 
00550     /// Return initialized mutex object.
00551     operator TObject&(void);
00552 
00553 protected:
00554     /// Initialize mutex.
00555     ///
00556     /// This method can be called many times it will return only after
00557     /// successful initialization of m_Mutex.
00558     
00559     void Initialize(void);
00560 
00561     /// Get initialized mutex object.
00562     TObject& Get(void);
00563 
00564 private:
00565     TObject m_Mutex;                ///< Mutex object.
00566 };
00567 
00568 
00569 
00570 /////////////////////////////////////////////////////////////////////////////
00571 ///
00572 /// CAutoInitializeStaticMutex --
00573 ///
00574 /// Define thread safe initializer static for SSystemMutex. 
00575 ///
00576 /// Needed on platforms where system mutex struct cannot be initialized at
00577 /// compile time (e.g. Win32).
00578 
00579 class CAutoInitializeStaticMutex
00580 {
00581 public:
00582     typedef SSystemMutex TObject;   ///< Simplified alias name for fast mutex
00583 
00584     /// Lock mutex.
00585     void Lock(void);
00586 
00587     /// Unlock mutex.
00588     void Unlock(void);
00589 
00590     /// Try locking the mutex.
00591     bool TryLock(void);
00592 
00593     /// Return initialized mutex object.
00594     operator TObject&(void);
00595 
00596 protected:
00597     /// Initialize mutex.
00598     ///
00599     /// This method can be called many times it will return only after
00600     /// successful initialization of m_Mutex.
00601     
00602     void Initialize(void);
00603 
00604     /// Get initialized mutex object.
00605     TObject& Get(void);
00606 
00607 private:
00608     TObject m_Mutex;                ///< Mutex object.
00609 };
00610 
00611 #endif
00612 
00613 /////////////////////////////////////////////////////////////////////////////
00614 //
00615 //  FAST MUTEX
00616 //
00617 //    CFastMutex::
00618 //    CFastMutexGuard::
00619 //
00620 
00621 
00622 
00623 /////////////////////////////////////////////////////////////////////////////
00624 ///
00625 /// CFastMutex --
00626 ///
00627 /// Simple mutex with fast lock/unlock functions.
00628 ///
00629 /// This mutex can be used instead of CMutex if it's guaranteed that
00630 /// there is no nesting. This mutex does not check nesting or owner.
00631 /// It has better performance than CMutex, but is less secure.
00632 
00633 class CFastMutex
00634 {
00635 public:
00636     /// Constructor.
00637     ///
00638     /// Creates mutex handle.
00639     CFastMutex(void);
00640 
00641     /// Destructor.
00642     ///
00643     /// Close mutex handle. No checks if it's still acquired.
00644     ~CFastMutex(void);
00645 
00646     /// Define Read Lock Guard.
00647     typedef CFastMutexGuard TReadLockGuard;
00648 
00649     /// Define Write Lock Guard.
00650     typedef CFastMutexGuard TWriteLockGuard;
00651 
00652     /// Acquire mutex for the current thread with no nesting checks.
00653     void Lock(void);
00654 
00655     /// Release mutex with no owner or nesting checks.
00656     void Unlock(void);
00657 
00658     /// Try locking the mutex.
00659     bool TryLock(void);
00660 
00661     /// Get SSystemFastMutex.
00662     operator SSystemFastMutex&(void);
00663 
00664 private:
00665 #if   !defined(NCBI_WIN32_THREADS)
00666     /// Get handle - Unix version.
00667     /// 
00668     /// Also used by CRWLock.
00669     TSystemMutex* GetHandle(void) { return &m_Mutex.m_Handle; }
00670 #elif !defined(NCBI_USE_CRITICAL_SECTION)
00671     /// Get handle - Windows version.
00672     /// 
00673     /// Also used by CRWLock.
00674     HANDLE GetHandle(void) { return m_Mutex.m_Handle; }
00675 #endif
00676 
00677     friend class CRWLock;
00678 
00679     /// Platform-dependent mutex handle, also used by CRWLock.
00680     SSystemFastMutex m_Mutex;
00681 
00682     /// Private copy constructor to disallow initialization.
00683     CFastMutex(const CFastMutex&);
00684 
00685     /// Private assignment operator to disallow assignment.
00686     CFastMutex& operator= (const CFastMutex&);
00687 };
00688 
00689 
00690 
00691 /////////////////////////////////////////////////////////////////////////////
00692 //
00693 //  MUTEX
00694 //
00695 //    CMutex::
00696 //    CMutexGuard::
00697 //
00698 
00699 
00700 
00701 /////////////////////////////////////////////////////////////////////////////
00702 ///
00703 /// CMutex --
00704 ///
00705 /// Mutex that allows nesting with runtime checks.
00706 ///
00707 /// Allows for recursive locks by the same thread. Checks the mutex
00708 /// owner before unlocking. This mutex should be used when performance
00709 /// is less important than data protection. For faster performance see
00710 /// CFastMutex.
00711 ///
00712 /// @sa
00713 ///   http://www.ncbi.nlm.nih.gov/books/bv.fcgi?rid=toolkit.section.ch_core.threads#ch_core.mutexes
00714 
00715 class CMutex
00716 {
00717 public:
00718     /// Constructor.
00719     CMutex(void);
00720 
00721     /// Destructor.
00722     ///
00723     /// Report error if the mutex is locked.
00724     ~CMutex(void);
00725 
00726     /// Define Read Lock Guard.
00727     typedef CMutexGuard TReadLockGuard;
00728 
00729     /// Define Write Lock Guard.
00730     typedef CMutexGuard TWriteLockGuard;
00731 
00732     /// Get SSystemMutex.
00733     operator SSystemMutex&(void);
00734 
00735     /// Lock mutex.
00736     ///
00737     /// Operation:
00738     /// - If the mutex is unlocked, then acquire it for the calling thread.
00739     /// - If the mutex is acquired by this thread, then increase the
00740     /// lock counter (each call to Lock() must have corresponding
00741     /// call to Unlock() in the same thread).
00742     /// - If the mutex is acquired by another thread, then wait until it's
00743     /// unlocked, then act like a Lock() on an unlocked mutex.
00744     void Lock(void);
00745 
00746     /// Try locking mutex.
00747     ///
00748     /// Try to acquire the mutex.
00749     /// @return
00750     ///   - On success, return TRUE, and acquire the mutex just as the Lock() does.
00751     ///   - If the mutex is already acquired by another thread, then return FALSE.
00752     /// @sa
00753     ///   Lock()
00754     bool TryLock(void);
00755 
00756     /// Unlock mutex.
00757     ///
00758     /// Operation:
00759     /// - If the mutex is acquired by this thread, then decrease the lock counter.
00760     /// - If the lock counter becomes zero, then release the mutex completely.
00761     /// - Report error if the mutex is not locked or locked by another thread.
00762     void Unlock(void);
00763 
00764 private:
00765     SSystemMutex m_Mutex;    ///< System mutex
00766 
00767     /// Private copy constructor to disallow initialization.
00768     CMutex(const CMutex&);
00769 
00770     /// Private assignment operator to disallow assignment.
00771     CMutex& operator= (const CMutex&);
00772 
00773     friend class CRWLock; ///< Allow use of m_Mtx and m_Owner members directly
00774 };
00775 
00776 
00777 
00778 /////////////////////////////////////////////////////////////////////////////
00779 ///
00780 /// CNoMutex --
00781 ///
00782 /// Fake mutex that does not lock anything.
00783 ///
00784 /// Allows to create template classes which use CMutex/CFastMutex/CNoMutex as
00785 /// an argument. In case of CNoMutex no real locking is performed.
00786 ///
00787 /// @sa
00788 ///   CNoLock
00789 
00790 typedef CNoLock CNoMutex;
00791 
00792 
00793 class CSpinLock;
00794 typedef CGuard<CSpinLock>  CSpinGuard;
00795 
00796 /////////////////////////////////////////////////////////////////////////////
00797 ///
00798 /// CSpinLock --
00799 ///
00800 /// Simple lock with lock/unlock functions even faster than in CFastMutex.
00801 ///
00802 /// This mutex can be used instead of CFastMutex when it's guaranteed that
00803 /// lock will be always held for a short period of time. CSpinLock doesn't do
00804 /// any system calls to wait for lock acquiring and relies on a fact that a
00805 /// couple of thread reschedulings will be enough for another thread to
00806 /// release the lock. As with CFastMutex no recursive locks are allowed.
00807 
00808 class CSpinLock
00809 {
00810 public:
00811     CSpinLock(void);
00812     ~CSpinLock(void);
00813 
00814     /// Define Read Lock Guard.
00815     typedef CSpinGuard TReadLockGuard;
00816     /// Define Write Lock Guard.
00817     typedef CSpinGuard TWriteLockGuard;
00818 
00819     /// Lock the mutex
00820     void Lock(void);
00821     /// Attempt to lock the mutex and return TRUE if it succeeded or FALSE if
00822     /// mutex is locked by other thread.
00823     bool TryLock(void);
00824     /// Unlock the mutex.
00825     /// There's no check that mutex is unlocked by the same thread that
00826     /// locked it.
00827     void Unlock(void);
00828 
00829 private:
00830     /// Prohibit copying of the object
00831     CSpinLock(const CSpinLock&);
00832     CSpinLock& operator= (const CSpinLock&);
00833 
00834     /// Flag showing if mutex is locked (non-NULL value) or unlocked
00835     /// (NULL value).
00836     void* volatile m_Value;
00837 };
00838 
00839 
00840 
00841 /////////////////////////////////////////////////////////////////////////////
00842 //
00843 //  RW-LOCK
00844 //
00845 //    CRWLock::
00846 //    CAutoRW::
00847 //    CReadLockGuard::
00848 //    CWriteLockGuard::
00849 //
00850 
00851 
00852 // Forward declaration of internal (platform-dependent) RW-lock representation
00853 class CInternalRWLock;
00854 class CRWLock;
00855 //class CReadLockGuard;
00856 //class CWriteLockGuard;
00857 
00858 
00859 
00860 /////////////////////////////////////////////////////////////////////////////
00861 ///
00862 /// SSimpleReadLock --
00863 ///
00864 /// Acquire a read lock
00865 template <class Class>
00866 struct SSimpleReadLock
00867 {
00868     void operator()(Class& inst) const
00869     {
00870         inst.ReadLock();
00871     }
00872 };
00873 
00874 typedef CGuard<CRWLock, SSimpleReadLock<CRWLock> > TReadLockGuard;
00875 typedef TReadLockGuard                             CReadLockGuard;
00876 
00877 
00878 /////////////////////////////////////////////////////////////////////////////
00879 ///
00880 /// SSimpleWriteLock --
00881 ///
00882 /// Acquire a write lock
00883 template <class Class>
00884 struct SSimpleWriteLock
00885 {
00886     void operator()(Class& inst) const
00887     {
00888         inst.WriteLock();
00889     }
00890 };
00891 
00892 typedef CGuard<CRWLock, SSimpleWriteLock<CRWLock> > TWriteLockGuard;
00893 typedef TWriteLockGuard                             CWriteLockGuard;
00894 
00895 
00896 /////////////////////////////////////////////////////////////////////////////
00897 ///
00898 /// CRWLock --
00899 ///
00900 /// Read/Write lock related data and methods.
00901 ///
00902 /// Allows multiple readers or single writer with recursive locks.
00903 /// R-after-W is considered to be a recursive Write-lock. W-after-R is not
00904 /// allowed.
00905 ///
00906 /// NOTE: When _DEBUG is not defined, does not always detect W-after-R
00907 /// correctly, so that deadlock may happen. Test your application
00908 /// in _DEBUG mode first!
00909 
00910 class  CRWLock
00911 {
00912 public:
00913     /// Flags (passed at construction time) for fine-tuning lock behavior.
00914     enum EFlags {
00915         /// Forbid further readers from acquiring the lock if any writers
00916         /// are waiting for it, to keep would-be writers from starving.
00917         fFavorWriters = 0x1
00918     };
00919     typedef int TFlags; ///< binary OR of EFlags
00920 
00921     /// Constructor.
00922     CRWLock(TFlags flags = 0);
00923 
00924     /// Destructor.
00925     ~CRWLock(void);
00926 
00927     /// Define Read Lock Guard.
00928     typedef CReadLockGuard TReadLockGuard;
00929 
00930     /// Define Write Lock Guard.
00931     typedef CWriteLockGuard TWriteLockGuard;
00932 
00933     /// Read lock.
00934     ///
00935     /// Acquire the R-lock. If W-lock is already acquired by
00936     /// another thread, then wait until it is released.
00937     void ReadLock(void);
00938 
00939     /// Write lock.
00940     ///
00941     /// Acquire the W-lock. If R-lock or W-lock is already acquired by
00942     /// another thread, then wait until it is released.
00943     void WriteLock(void);
00944 
00945     /// Try read lock.
00946     ///
00947     /// Try to acquire R-lock and return immediately.
00948     /// @return
00949     ///   TRUE if the R-lock has been successfully acquired;
00950     ///   FALSE, otherwise.
00951     bool TryReadLock(void);
00952 
00953     /// Try write lock.
00954     ///
00955     /// Try to acquire W-lock and return immediately.
00956     /// @return
00957     ///   TRUE if the W-lock has been successfully acquired;
00958     ///   FALSE, otherwise.
00959     bool TryWriteLock(void);
00960 
00961     /// Release the RW-lock.
00962     void Unlock(void);
00963 
00964 private:
00965     enum EInternalFlags {
00966         /// Keep track of which threads have read locks
00967         fTrackReaders = 0x40000000
00968     };
00969 
00970     TFlags                     m_Flags; ///< Configuration flags
00971 
00972     auto_ptr<CInternalRWLock>  m_RW;    ///< Platform-dependent RW-lock data
00973 
00974     volatile CThreadSystemID   m_Owner; ///< Writer ID, one of the readers ID
00975 
00976     volatile int               m_Count; ///< Number of readers (if >0) or
00977                                         ///< writers (if <0)
00978 
00979     volatile unsigned int      m_WaitingWriters; ///< Number of writers waiting;
00980                                                  ///< zero if not keeping track
00981 
00982     vector<CThreadSystemID>    m_Readers;   ///< List of all readers or writers
00983                                             ///< for debugging
00984 
00985     bool x_MayAcquireForReading(CThreadSystemID self_id);
00986 
00987     /// Private copy constructor to disallow initialization.
00988     CRWLock(const CRWLock&);
00989 
00990     /// Private assignment operator to disallow assignment.
00991     CRWLock& operator= (const CRWLock&);
00992 };
00993 
00994 
00995 class CFastRWLock;
00996 
00997 /////////////////////////////////////////////////////////////////////////////
00998 ///
00999 /// SSimpleReadUnlock --
01000 ///
01001 /// Release a read lock
01002 
01003 template <class Class>
01004 struct SSimpleReadUnlock
01005 {
01006     void operator()(Class& inst) const
01007     {
01008         inst.ReadUnlock();
01009     }
01010 };
01011 
01012 typedef CGuard< CFastRWLock,
01013                 SSimpleReadLock  <CFastRWLock>,
01014                 SSimpleReadUnlock<CFastRWLock> >  CFastReadGuard;
01015 
01016 /////////////////////////////////////////////////////////////////////////////
01017 ///
01018 /// SSimpleWriteUnlock --
01019 ///
01020 /// Release a write lock
01021 
01022 template <class Class>
01023 struct SSimpleWriteUnlock
01024 {
01025     void operator()(Class& inst) const
01026     {
01027         inst.WriteUnlock();
01028     }
01029 };
01030 
01031 typedef CGuard< CFastRWLock,
01032                 SSimpleWriteLock  <CFastRWLock>,
01033                 SSimpleWriteUnlock<CFastRWLock> > CFastWriteGuard;
01034 
01035 
01036 /////////////////////////////////////////////////////////////////////////////
01037 ///
01038 /// CFastRWLock --
01039 ///
01040 /// Fast implementation of Read/Write lock.
01041 ///
01042 /// Allows multiple readers or single writer. Behaves similar to CRWLock
01043 /// though with some assumptions and limitations:
01044 /// - Does not try to detect recursive locks, actually any attempt to lock
01045 ///   recursively will end up in undefined behavior (the only exception is
01046 ///   read-after-read lock - this is ok).
01047 /// - Does not remember when and where it was actually locked, so that it will
01048 ///   not be able to recover after call to ReadUnlock() or WriteUnlock() if it
01049 ///   was not preceded by call to corresponding Lock() method. So the best way
01050 ///   to use it is just via CFastReadGuard and CFastWriteGuard.
01051 /// - Assumes that read lock is always held for a very small amount of time,
01052 ///   though write lock can be held as long as you want. Failure to comply
01053 ///   with this assumption will result in heavy CPU usage when trying to
01054 ///   acquire write lock while long read lock is held.
01055 /// - Assumes that write lock is taken pretty rarely so that there is no
01056 ///   possibility of their overlapping (actually it easily resolves
01057 ///   overlapping though with possibility of readers starvation).
01058 /// - As a consequence of previous assumption assumes that writer
01059 ///   "favoredness" (see fFavorWriters in CRWLock) is always needed.
01060 /// - Assumes that there will not be too much simultaneous read locks
01061 ///   acquired, at least not more than 1048576.
01062 ///
01063 /// All these assumptions and limitations allowed to make extremely
01064 /// lightweight implementation of RWLock where the most common operation -
01065 /// read lock and unlock - is performed very quickly without blocking each
01066 /// other.
01067 
01068 class  CFastRWLock
01069 {
01070 public:
01071     typedef CFastReadGuard  TReadLockGuard;
01072     typedef CFastWriteGuard TWriteLockGuard;
01073 
01074     CFastRWLock(void);
01075     ~CFastRWLock(void);
01076 
01077     /// Acquire read lock
01078     void ReadLock(void);
01079     /// Release read lock
01080     void ReadUnlock(void);
01081 
01082     /// Acquire write lock
01083     void WriteLock(void);
01084     /// Release write lock
01085     void WriteUnlock(void);
01086 
01087 private:
01088     CFastRWLock(const CFastRWLock&);
01089     CFastRWLock& operator= (const CFastRWLock&);
01090 
01091     enum {
01092         /// Number in lock count showing that write lock is acquired.
01093         kWriteLockValue = 0x100000
01094     };
01095 
01096     /// Number of read locks acquired or value of kWriteLockValue if write
01097     /// lock was acquired
01098     CAtomicCounter  m_LockCount;
01099     /// Mutex implementing write lock
01100     CFastMutex      m_WriteLock;
01101 };
01102 
01103 
01104 
01105 class CYieldingRWLock;
01106 class CRWLockHolder;
01107 
01108 /// Type of locking provided by CYieldingRWLock
01109 enum ERWLockType
01110 {
01111     eReadLock  = 0,
01112     eWriteLock = 1
01113 };
01114 
01115 
01116 /// Interface for receiving messages about state changes in CRWLockHolder.
01117 /// Implementations of this interface should inherit from CObjectEx to allow
01118 /// to take smart references on them.
01119 class  IRWLockHolder_Listener
01120 {
01121 public:
01122     virtual ~IRWLockHolder_Listener(void);
01123 
01124     /// Callback called when lock represented by CRWLockHolder is acquired
01125     virtual void OnLockAcquired(CRWLockHolder* holder) = 0;
01126 
01127     /// Callback called when lock represented by CRWLockHolder is released
01128     virtual void OnLockReleased(CRWLockHolder* holder) = 0;
01129 };
01130 
01131 /// Types of smart references to IRWLockHolder_Listener
01132 typedef CIRef<IRWLockHolder_Listener>      TRWLockHolder_ListenerRef;
01133 typedef CWeakIRef<IRWLockHolder_Listener>  TRWLockHolder_ListenerWeakRef;
01134 
01135 
01136 /// Interface for factory creating CRWLockHolder objects.
01137 /// Default interface implementation supports pooling of CRWLockHolder objects
01138 /// to avoid extensive use of new/delete
01139 class  IRWLockHolder_Factory
01140 {
01141 public:
01142     virtual ~IRWLockHolder_Factory(void);
01143 
01144     /// Obtain new CRWLockHolder object for given CYieldingRWLock and
01145     /// necessary lock type.
01146     virtual CRWLockHolder* CreateHolder(CYieldingRWLock* lock,
01147                                         ERWLockType      typ) = 0;
01148 
01149     /// Free unnecessary (and unreferenced by anybody) CRWLockHolder object
01150     virtual void DeleteHolder(CRWLockHolder* holder) = 0;
01151 };
01152 
01153 /// Holder of the lock inside CYieldingRWLock.
01154 /// This class should be used for 2 different reasons:
01155 /// - while IsLockAcquired() is not true the requested lock is not provided
01156 ///   to you, so this object will be as a signal for you to continue operation
01157 /// - the lock is held while this object is alive, though it's always better
01158 ///   to explicitly call ReleaseLock().
01159 class  CRWLockHolder : public CObject
01160 {
01161     friend class CYieldingRWLock;
01162 
01163 public:
01164     /// Create lock holder bound to given object factory
01165     CRWLockHolder(IRWLockHolder_Factory* factory);
01166 
01167     virtual ~CRWLockHolder(void);
01168 
01169     /// Get factory which this object was created from
01170     IRWLockHolder_Factory* GetFactory(void) const;
01171 
01172     /// Get lock object that is locked by this holder
01173     CYieldingRWLock* GetRWLock(void) const;
01174 
01175     /// Get type of lock held
01176     ERWLockType GetLockType(void) const;
01177 
01178     /// Check if lock requested is already granted
01179     bool IsLockAcquired(void) const;
01180 
01181     /// Release the lock held or cancel request for the lock
01182     void ReleaseLock(void);
01183 
01184     /// Add object keeping track of holder state changes
01185     void AddListener(IRWLockHolder_Listener* listener);
01186 
01187     /// Remove object keeping track of holder state changes
01188     void RemoveListener(IRWLockHolder_Listener* listener);
01189 
01190 public:
01191     /// Initialize holder for given CYieldingRWLock and necessary lock type.
01192     /// Method is for use only inside IRWLockHolder_Factory implementation
01193     void Init(CYieldingRWLock* lock, ERWLockType typ);
01194 
01195     /// Reset holder to be able to use it later (after calling Init() )
01196     void Reset(void);
01197 
01198 private:
01199     CRWLockHolder(const CRWLockHolder&);
01200     CRWLockHolder& operator= (const CRWLockHolder&);
01201 
01202     /// Callback called at the moment when lock is granted
01203     void x_OnLockAcquired(void);
01204     /// Callback called at the moment when lock is released. Method is not
01205     /// called if request for lock was canceled before it was actually
01206     /// granted.
01207     void x_OnLockReleased(void);
01208     /// "Delete" this holder after last reference was removed.
01209     /// Actually deletes using factory's DeleteHolder().
01210     virtual void DeleteThis(void) const;
01211 
01212 
01213     typedef list<TRWLockHolder_ListenerWeakRef> TListenersList;
01214 
01215     /// Factory created the holder
01216     IRWLockHolder_Factory* m_Factory;
01217     /// Lock object the holder is assigned to
01218     CYieldingRWLock*       m_Lock;
01219     /// Type of lock held
01220     ERWLockType            m_Type;
01221     /// Flag if lock was acquired
01222     bool                   m_LockAcquired;
01223     /// Mutex for operating listeners
01224     CSpinLock              m_ObjLock;
01225     /// List of holder listeners
01226     TListenersList         m_Listeners;
01227 };
01228 
01229 /// Type that should be always used to store pointers to CRWLockHolder
01230 typedef CRef<CRWLockHolder> TRWLockHolderRef;
01231 
01232 
01233 /// Read/write lock without blocking calls.
01234 ///
01235 /// Neither R-lock nor W-lock is bound to thread acquired it and can be
01236 /// released in any other thread. Any lock is bound to CRWLockHolder object
01237 /// only.
01238 /// Allows to exist several readers at a time or one writer. Always respects
01239 /// the time of lock request. I.e. no new readers are granted access if there
01240 /// is some writer waiting for access and no new writers are granted access if
01241 /// there is some readers waiting for access (while another writer is
01242 /// working).
01243 /// Can be customizable by instance of IRWLockHolder_Factory to adopt custom
01244 /// memory management for CRWLockHolder objects.
01245 class  CYieldingRWLock
01246 {
01247     friend class CRWLockHolder;
01248 
01249 public:
01250     /// Create read/write lock with custom holders factory.
01251     /// By default (if factory == NULL) pooling of CRWLockHolder will be used.
01252     CYieldingRWLock(IRWLockHolder_Factory* factory = NULL);
01253 
01254     /// It is fatal error to destroy the object while some locks are pending.
01255     /// Thus this object should be destroyed only after calls to ReleaseLock()
01256     /// for all CRWLockHolder objects.
01257     ~CYieldingRWLock(void);
01258 
01259     /// Read lock.
01260     /// Method returns immediately no matter if lock is granted or not. If
01261     /// lock is not granted then request for lock is remembered and will be
01262     /// granted later unless CRWLockHolder::ReleaseLock() is called (or object
01263     /// is deleted).
01264     TRWLockHolderRef AcquireReadLock(void);
01265 
01266     /// Write lock.
01267     /// Method returns immediately no matter if lock is granted or not. If
01268     /// lock is not granted then request for lock is remembered and will be
01269     /// granted later unless CRWLockHolder::ReleaseLock() is called (or object
01270     /// is deleted).
01271     TRWLockHolderRef AcquireWriteLock(void);
01272 
01273     /// General method to request read or write lock.
01274     TRWLockHolderRef AcquireLock(ERWLockType lock_type);
01275 
01276     /// Check if any type of lock on this object is held
01277     bool IsLocked(void);
01278 
01279 private:
01280     typedef deque<TRWLockHolderRef>  THoldersList;
01281 
01282     /// Main implementation releasing lock
01283     void x_ReleaseLock(CRWLockHolder* holder);
01284 
01285 
01286     /// Factory creating CRWLockHolder objects
01287     IRWLockHolder_Factory* m_Factory;
01288     /// Main locking mutex for object operations
01289     CSpinLock              m_ObjLock;
01290     /// Number of locks granted on this object by type
01291     int                    m_Locks[2];
01292     /// Queue for waiting lock requests
01293     THoldersList           m_LockWaits;
01294 };
01295 
01296 
01297 
01298 /////////////////////////////////////////////////////////////////////////////
01299 ///
01300 /// CSemaphore --
01301 ///
01302 /// Implement the semantics of an application-wide semaphore.
01303 
01304 class  CSemaphore
01305 {
01306 public:
01307     /// Constructor.
01308     ///
01309     /// @param
01310     ///   int_count   The initial value of the semaphore.
01311     ///   max_count   Maximum value that semaphore value can be incremented to.
01312     CSemaphore(unsigned int init_count, unsigned int max_count);
01313 
01314     /// Destructor.
01315     ///
01316     /// Report error if the semaphore is locked.
01317     ~CSemaphore(void);
01318 
01319     /// Wait on semaphore.
01320     ///
01321     /// Decrement the counter by one. If the semaphore's count is zero then
01322     /// wait until it's not zero.
01323     void Wait(void);
01324 
01325     /// Timed wait.
01326     ///
01327     /// Wait up to timeout_sec + timeout_nsec/1E9 seconds for the
01328     /// semaphore's count to exceed zero.  If that happens, decrement
01329     /// the counter by one and return TRUE; otherwise, return FALSE.
01330     bool TryWait(unsigned int timeout_sec = 0, unsigned int timeout_nsec = 0);
01331 
01332     /// Increment the semaphore by "count".
01333     ///
01334     /// Do nothing and throw an exception if counter would exceed "max_count".
01335     void Post(unsigned int count = 1);
01336 
01337 private:
01338     struct SSemaphore* m_Sem;  ///< System-specific semaphore data.
01339 
01340     /// Private copy constructor to disallow initialization.
01341     CSemaphore(const CSemaphore&);
01342 
01343     /// Private assignment operator to disallow assignment.
01344     CSemaphore& operator= (const CSemaphore&);
01345 };
01346 
01347 
01348 /* @} */
01349 
01350 
01351 #include <corelib/ncbimtx.inl>
01352 
01353 /////////////////////////////////////////////////////////////////////////////
01354 
01355 END_NCBI_SCOPE
01356 
01357 #endif  /* NCBIMTX__HPP */
01358 
01359 

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