Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

311 lines
6.9 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996
//
// File: readwrit.hxx
//
// Contents: Single writer / multiple reader locking class
//
// Classes: CReadWriteAccess, CReadAccess, CWriteAccess
//
// History: 15-Feb-96 dlee Created
// 2-Dec-96 dlee Re-wrote using Kyle's algorithm
//
//----------------------------------------------------------------------------
#pragma once
//+-------------------------------------------------------------------------
//
// Class: CReadWriteLockRecord
//
// Purpose: Atomically maintains a count of readers and writers.
//
// Notes: Reads are atomic -- there is no need for Interlocked access
//
// History: 23-Feb-96 dlee Created
// 02-Dec-96 dlee Renamed and moved from proplock.hxx
//
//----------------------------------------------------------------------------
class CReadWriteLockRecord
{
public:
void Init() { _cReaders = 0; _cWriters = 0; }
#if CIDBG == 1
BOOL LokIsBeingWrittenTwice() { return _cWriters > 1; }
#endif
BOOL isBeingRead() { return 0 != _cReaders; }
BOOL isBeingWritten() { return 0 != _cWriters; }
void AddReader() { InterlockedIncrement( &_cReaders ); }
void RemoveReader() { InterlockedDecrement( &_cReaders ); }
void AddWriter() { InterlockedIncrement( &_cWriters ); }
void RemoveWriter() { InterlockedDecrement( &_cWriters ); }
private:
LONG _cWriters; // 0 or 1
LONG _cReaders; // # of active readers
};
//+-------------------------------------------------------------------------
//
// Class: CReadWriteAccess
//
// Purpose: Implements single writer / multiple reader
//
// History: 15-Feb-96 dlee Created
//
//----------------------------------------------------------------------------
class CReadWriteAccess
{
public:
CReadWriteAccess()
{
_rec.Init();
}
~CReadWriteAccess()
{
}
void GetReadAccess()
{
do
{
if ( _rec.isBeingWritten() )
SyncRead();
_rec.AddReader();
if ( !_rec.isBeingWritten() )
break;
else
SyncReadDecrement();
} while ( TRUE );
}
void ReleaseReadAccess()
{
if ( _rec.isBeingWritten() )
{
CLock lock( _mtxWrite );
_rec.RemoveReader();
if ( !_rec.isBeingRead() )
{
LokInitWriteEvent();
_evtWrite->Set();
}
}
else
{
_rec.RemoveReader();
if ( _rec.isBeingWritten() )
{
CLock lock( _mtxWrite );
if ( !_rec.isBeingRead() )
{
LokInitWriteEvent();
_evtWrite->Set();
}
}
}
}
void GetWriteAccess()
{
_mtxWriterBusy.Request();
_rec.AddWriter();
BOOL fWait = FALSE;
{
CLock lock( _mtxWrite );
Win4Assert( !_rec.LokIsBeingWrittenTwice() );
if ( _rec.isBeingRead() )
{
LokInitWriteEvent();
_evtWrite->Reset();
fWait = TRUE;
}
}
if ( fWait )
_evtWrite->Wait();
}
void ReleaseWriteAccess()
{
{
CLock lock( _mtxWrite );
_rec.RemoveWriter();
LokInitReadEvent();
_evtRead->Set();
}
_mtxWriterBusy.Release();
}
CMutexSem & WriteMutex() { return _mtxWrite; }
private:
void SyncRead()
{
do
{
BOOL fNeedToWait = FALSE;
{
CLock lock( _mtxWrite );
if ( _rec.isBeingWritten() )
{
LokInitReadEvent();
_evtRead->Reset();
fNeedToWait = TRUE;
}
}
if ( fNeedToWait )
_evtRead->Wait();
} while ( _rec.isBeingWritten() );
}
void SyncReadDecrement()
{
BOOL fDecrementRead = TRUE;
do
{
BOOL fNeedToWait = FALSE;
{
CLock lock( _mtxWrite );
if ( _rec.isBeingWritten() )
{
if ( fDecrementRead )
{
_rec.RemoveReader();
if ( !_rec.isBeingRead() )
{
LokInitWriteEvent();
_evtWrite->Set();
}
}
LokInitReadEvent();
_evtRead->Reset();
fNeedToWait = TRUE;
}
else
{
if ( fDecrementRead )
_rec.RemoveReader();
}
fDecrementRead = FALSE;
}
if ( fNeedToWait )
_evtRead->Wait();
} while ( _rec.isBeingWritten() );
Win4Assert( !fDecrementRead );
}
void LokInitReadEvent()
{
if ( _evtRead.IsNull() )
_evtRead.Set( new CEventSem() );
}
void LokInitWriteEvent()
{
if ( _evtWrite.IsNull() )
_evtWrite.Set( new CEventSem() );
}
CReadWriteLockRecord _rec;
CMutexSem _mtxWriterBusy;
CMutexSem _mtxWrite;
XPtr<CEventSem> _evtRead;
XPtr<CEventSem> _evtWrite;
};
//+-------------------------------------------------------------------------
//
// Class: CReadAccess
//
// Purpose: Grabs a read lock in the constructor, and releases it in
// the destructor
//
// History: 15-Feb-96 dlee Created
//
//----------------------------------------------------------------------------
class CReadAccess
{
public:
CReadAccess( CReadWriteAccess & rwAccess ) :
_rwAccess( rwAccess )
{
_rwAccess.GetReadAccess();
}
~CReadAccess()
{
_rwAccess.ReleaseReadAccess();
}
private:
CReadWriteAccess & _rwAccess;
};
//+-------------------------------------------------------------------------
//
// Class: CWriteAccess
//
// Purpose: Grabs a write lock in the constructor, and releases it in
// the destructor
//
// History: 15-Feb-96 dlee Created
//
//----------------------------------------------------------------------------
class CWriteAccess
{
public:
CWriteAccess( CReadWriteAccess & rwAccess ) :
_rwAccess( rwAccess )
{
_rwAccess.GetWriteAccess();
}
~CWriteAccess()
{
_rwAccess.ReleaseWriteAccess();
}
private:
CReadWriteAccess & _rwAccess;
};