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
1.4.6
Modified on Mon Dec 07 16:20:35 2009 by modify_doxy.py rev. 173732