/*-------------------------------------------------------- rwlock.h CReadWriteLock class provides functions that allow threads to lock any resource in two different modes (read-mode and write-mode). The class will allow multiple reader threads to access the resource simultaneously, but will make sure that a writer thread doesn't access the resource when reader threads or a writer thread is currently accessing the resource. The class also assures fairness in access i.e. the access will be regulated by a first-come-first-in policy. Note:- ALL the functions in the class are INLINE functions. So, this header can be directly used in the source. Copyright (C) 1995 Microsoft Corporation All rights reserved. Authors: rsraghav R.S. Raghavan History: 04-20-95 rsraghav Created. -------------------------------------------------------*/ #ifdef __cplusplus // this file should be include only if this is // is included in a c++ source file. #ifndef _RWLOCK_H_ #define _RWLOCK_H_ #if defined(DEBUG) && defined(INLINE) #undef THIS_FILE static char BASED_CODE RWLOCK_H[] = "rwlock.h"; #define THIS_FILE RWLOCK_H #endif #include #define INLINE_EXPORT_SPEC __declspec( dllexport) typedef enum {RWLOCK_READ_MODE, RWLOCK_WRITE_MODE} RWLOCK_MODE; ////////////////////////////////////////////////////////////////////// // CReadWriteLock - Class that can be used to regulate read-write // access to resource, where multiple readers are // allowed simultaneously, but writers are excluded // from each other and from the readers. class INLINE_EXPORT_SPEC CReadWriteLock { HANDLE hResource; CRITICAL_SECTION csReader; CRITICAL_SECTION csWriter; DWORD cReaders; DWORD cWriteRecursion; public: CReadWriteLock() // object constructor { cReaders =0; cWriteRecursion = 0; hResource = CreateEvent(NULL, FALSE, TRUE, NULL); // no manual reset & initial state is signalled InitializeCriticalSection(&csReader); InitializeCriticalSection(&csWriter); } ~CReadWriteLock() // object destructor { if (hResource) CloseHandle(hResource); DeleteCriticalSection(&csReader); DeleteCriticalSection(&csWriter); } CReadWriteLock *PrwLock() { return this; } BOOL FInit() { return (BOOL)hResource; } void LockReadMode() // Get read access to the resource { EnterCriticalSection(&csWriter); LeaveCriticalSection(&csWriter); EnterCriticalSection(&csReader); if (!cReaders) { if (hResource) WaitForSingleObject(hResource, INFINITE); } cReaders++; LeaveCriticalSection(&csReader); } int LockReadModeEx(int iTimeOut) // Get read access to the resource w/ Timeout { int status = 0; EnterCriticalSection(&csWriter); LeaveCriticalSection(&csWriter); EnterCriticalSection(&csReader); if (!cReaders) { if (hResource) { status = WaitForSingleObject(hResource, iTimeOut); if (status == WAIT_TIMEOUT) { status = -1; } else { status = 0; } } } cReaders++; LeaveCriticalSection(&csReader); return status; } void UnlockReadMode() // Relinquish read access to the resource { EnterCriticalSection(&csReader); if (!(--cReaders)) { if (hResource) SetEvent(hResource); } LeaveCriticalSection(&csReader); } void LockCSUnderRead() { EnterCriticalSection(&csReader); } void UnlockCSUnderRead() { LeaveCriticalSection(&csReader); } void LockWriteMode() // Get write access to the resource { EnterCriticalSection(&csWriter); if (!cWriteRecursion) { if (hResource) WaitForSingleObject(hResource, INFINITE); } cWriteRecursion++; } int LockWriteModeEx(int iTimeOut) // Get write access to the resource { int status = 0; EnterCriticalSection(&csWriter); if (!cWriteRecursion) { if (hResource) { status = WaitForSingleObject(hResource, iTimeOut); if (status == WAIT_TIMEOUT) { LeaveCriticalSection(&csWriter); status = -1; } else { status = 0; } } } if (status == 0) cWriteRecursion++; return status; } void UnlockWriteMode() // Relinquish write access to the resource { if (!(--cWriteRecursion)) { if (hResource) SetEvent(hResource); } LeaveCriticalSection(&csWriter); } }; ////////////////////////////////////////////////////////////////////// // Following class is just a utility class - users don't need to // necessarily use this class for obtaining read-write lock functionalities. ////////////////////////////////////////////////////////////////////// // CScopeRWLock - This can be used to lock the given CReadWriteLock // object for the rest of the scope. The user just // needs to define this object in the scope by passing // a pointer to the CReadWriteLock object in the constructor. // When this CScopeRWLock object goes out of scope the // CReadWriteLock object will automatically be unlocked. // This is provided just for user convenience so that the // user can choose to avoid remembering to unlock the object // before every possible return/break path of the scope. // Use the RWLOCK_READ_MODE or RWLOCK_WRITE_MODE in the constructor // to indicate which type of access is requested. // Assumption:- CReadWriteLock object used here is expected to // be valid at lease until the end of the scope. class INLINE_EXPORT_SPEC CScopeRWLock { CReadWriteLock *m_prwLock; LPCRITICAL_SECTION m_pcs; RWLOCK_MODE m_rwMode; public: CScopeRWLock(CReadWriteLock * prwLock, RWLOCK_MODE rwMode) { m_prwLock = prwLock; m_pcs = NULL; m_rwMode = rwMode; if (m_prwLock) { if (m_rwMode == RWLOCK_READ_MODE) m_prwLock->LockReadMode(); else if (m_rwMode == RWLOCK_WRITE_MODE) m_prwLock->LockWriteMode(); } } CScopeRWLock(LPCRITICAL_SECTION pcsLock) { m_pcs = pcsLock; m_prwLock = NULL; if (m_pcs) EnterCriticalSection(m_pcs); } ~CScopeRWLock() { if (m_prwLock) { if (m_rwMode == RWLOCK_READ_MODE) m_prwLock->UnlockReadMode(); else if (m_rwMode == RWLOCK_WRITE_MODE) m_prwLock->UnlockWriteMode(); } if (m_pcs) { LeaveCriticalSection(m_pcs); } } }; #endif // _RWLOCK_H_ #endif // #if __cplusplus