/*++ rwnew.h This file defines several variations of Reader/Writer locks with different properties regarding handles used, and other implementation details. Also defined are some variations of CRITICAL_SECTIONS which use fewer or no handles. --*/ #ifndef _RWNEW_H #define _RWNEW_H #ifdef _RW_IMPLEMENTATION_ #define _RW_INTERFACE_ __declspec( dllexport ) #else #define _RW_INTERFACE_ __declspec( dllimport ) #endif #pragma warning( disable:4251 ) #include #include "lockq.h" #include "rwintrnl.h" class _RW_INTERFACE_ CCritSection { private : // // Handle of thread owning the lock ! // HANDLE m_hOwner ; // // Count of Recursive Calls // long m_RecursionCount ; // // Count used to see who gets the lock next ! // long m_lock ; // // Queue of waiting threads // CSingleReleaseQueue m_queue ; // // Copying of these objects is not allowed !!!! // CCritSection( CCritSection& ) ; CCritSection& operator=( CCritSection& ) ; public : #ifdef DEBUG DWORD m_dwThreadOwner ; #endif // // Construct a critical section object // CCritSection( ) : m_queue( FALSE ), m_hOwner( INVALID_HANDLE_VALUE ), m_RecursionCount( 0 ), m_lock( -1 ) { } // // Acquire the critical section // void Enter( CWaitingThread& myself ) ; // // Another version which acquires the critical section - // creates its own CWaitingThread object ! // void Enter() ; // // REturns TRUE if the lock is available right now ! // BOOL TryEnter( CWaitingThread& myself ) ; // // Returns TRUE if we can get the lock right now ! // BOOL TryEnter() { CWaitingThread myself ; return TryEnter( myself ) ; } // // Release the critical section ! // void Leave() ; } ; // // This version of critical section is more like an event - doesn't // care who releases locks - and doesn't handle recursive grabs ! // class _RW_INTERFACE_ CSimpleCritSection { private : // // Count used to see who gets the lock next ! // long m_lock ; // // Queue of waiting threads // CSingleReleaseQueue m_queue ; // // Copying of these objects is not allowed !!!! // CSimpleCritSection( CCritSection& ) ; CSimpleCritSection& operator=( CCritSection& ) ; public : #ifdef DEBUG DWORD m_dwThreadOwner ; #endif // // Construct a critical section object // CSimpleCritSection( ) : m_queue( FALSE ), #ifdef DEBUG m_dwThreadOwner( 0 ), #endif m_lock( -1 ) { } // // Acquire the critical section // void Enter( CWaitingThread& myself ) ; // // Another version which acquires the critical section - // creates its own CWaitingThread object ! // void Enter() ; // // REturns TRUE if the lock is available right now ! // BOOL TryEnter( CWaitingThread& myself ) ; // // Returns TRUE if we can get the lock right now ! // BOOL TryEnter() { CWaitingThread myself ; return TryEnter( myself ) ; } // // Release the critical section ! // void Leave() ; } ; // // Another class which tries to create Reader/Write locks with // no handles !! // class _RW_INTERFACE_ CShareLockNH { private : // // Lock grabbed by writers to have exclusive access // CSimpleCritSection m_lock ; // // Number of readers who have grabbed the Read Lock - // Negative if a writer is waiting ! // volatile long m_cReadLock ; // // Number of Readers who have left the lock since a // writer tried to grab it ! // volatile long m_cOutReaders ; // // Number of readers who are entering the lock after // being blocked !!! // volatile long m_cOutAcquiringReaders ; // // Number of threads needing m_lock to be held right now ! // volatile long m_cExclusiveRefs ; // // Handle that all the readers who are waiting try to grab ! // volatile HANDLE m_hWaitingReaders ; // // Handle that the single writer waiting for the lock is trying // to grab ! // volatile HANDLE m_hWaitingWriters ; void inline WakeReaders() ; // // The internal work of ShareLock - does a lot more of the stuff required // when a writer is present !!! // void ShareLockInternal() ; // // The internal work of ShareLock - does a lot more of the stuff required // when a writer is present !!! // void ShareUnlockInternal() ; // // You may not copy these objects - so this lock is private ! // CShareLockNH( CShareLockNH& ) ; // // You may not copy through assignment - so this operator is private ! // CShareLockNH& operator=( CShareLockNH& ) ; public : // // Construction of CShareLockNH() objects always succeeds and there // are no error cases ! // CShareLockNH() ; // // Grab the lock Shared - other threads may pass through ShareLock() as well // void ShareLock() ; // // Releases the lock - if we are the last reader to leave writers may // start to enter the lock ! // void ShareUnlock() ; // // Grab the lock Exclusively - no other readers or writers may enter !! // void ExclusiveLock() ; // // Release the Exclusive Locks - if there are readers waiting they // will enter before other waiting writers ! // void ExclusiveUnlock() ; // // Convert an ExclusiveLock to a Shared - this cannot fail ! // void ExclusiveToShared() ; // // Convert a Shared Lock to an Exclusive one - this can fail - returns // TRUE if successfull ! // BOOL SharedToExclusive() ; // // Return TRUE if we can get the lock shared. Only fails when // somebody is attempting or has the lock exclusively, we will enter // if there are only other readers in the lock. // BOOL TryShareLock() ; // // Return TRUE if we can get the lock Exclusively. Only succeeds // when nobody else is near the lock. // BOOL TryExclusiveLock() ; // // PartialLocks - // // Partial Locks are similar to Exclusive Locks - only one thread // can successfully call PartialLock(), any other threads calling // PartialLock() or ExclusiveLock() will block. // HOWEVER - while a PartialLock() is held, Readers (threads calling // ShareLock()) may enter the lock. // void PartialLock() ; // // Release the PartialLock - Other Exclusive() or Partial lock acquirers // may now enter. // void PartialUnlock() ; // // Convert a Partial Lock to an Exclusive Lock. This function is // guaranteed to succeed, HOWEVER a lock can only be converted with // this function once, i.e. a thread doing // PartialLock() ; // FirstPartialToExclusive() ; // ExclusiveToPartial() ; // FirstPartialToExclusive() ; // will have problems - the second call to FirstPartialToExclusive() // may mess up the lock state and cause the lock to fail horribly. // If a user wishes to convert as above they must have a call sequence like : // // PartialLock() ; // FirstPartialToExclusive() or PartialToExclusive() ; // ExclusiveToPartial() ; // PartialToExclusive() ; // // If you change lock states more than once - you take your chances ! // void FirstPartialToExclusive() ; // // Returns TRUE if we can get the lock Exclusively, otherwise // we return FALSE with the lock remaining in the Partially held state. // // NOTE : NYI in CShareLockNH - will always return FALSE ! // BOOL PartialToExclusive() ; // // We can always go from an ExclusiveLock() to a PartialLock() state. // void ExclusiveToPartial() ; // // We can always go from a PartialLock() state to a SharedLock() state // void PartialToShared() ; // // Returns TRUE if we can get the lock Partially ! // If it returns FALSE we remain with the lock held Shared() // BOOL SharedToPartial() ; // // Returns TRUE only if no other threads are trying to get the lock // ExclusiveLy or Partially ! // BOOL TryPartialLock() ; } ; // // This is a utility function to get an Event Handle we save // for each thread - the handle is Created as: // CreateEvent( NULL, // FALSE, // FALSE, // NULL ) ; // This results in an auto-reset event which goes back to non signalled whenever a thread // is released. // HANDLE _RW_INTERFACE_ GetPerThreadEvent() ; #endif // _RWNEW_H_