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.
169 lines
5.3 KiB
169 lines
5.3 KiB
//
|
|
// This file contains test implmentations of reader and writer locks.
|
|
// These are intended to be used with the template class in rw.h so that
|
|
// different implementations can be plugged in and tested.
|
|
//
|
|
// The semantics of the read/write classes should be as follows :
|
|
// Functions CAN NOT be recursively called,
|
|
// Multiple Readers should be able to enter the lock
|
|
// Only a single writer may execute at a time.
|
|
//
|
|
|
|
|
|
#ifndef WIN16
|
|
|
|
|
|
#include <windows.h>
|
|
#include <limits.h>
|
|
|
|
#define Assert(x) // Just define a dummy Assert, so we don't get
|
|
// compilation errors from exrwlck.h
|
|
|
|
#include "badstrfunctions.h"
|
|
#include "exrwlck.h"
|
|
|
|
#ifdef DEBUG
|
|
#ifndef _VALIDATE
|
|
#define _VALIDATE( f ) if( (f) ) ; else DebugBreak()
|
|
#endif
|
|
#else
|
|
#ifndef _VALIDATE
|
|
#define _VALIDATE( f )
|
|
#endif
|
|
#endif
|
|
|
|
long const BlockValue = (-LONG_MAX) / 2;
|
|
// Large in magnitude, negative value. Used to
|
|
// indicate a waiting writer in cReadLock
|
|
|
|
|
|
CExShareLock::CExShareLock( ) : cReadLock( 0 ), cOutRdrs( 0 ) {
|
|
InitializeCriticalSection( &critWriters ) ;
|
|
hWaitingWriters = CreateSemaphore( NULL, 0, 1, NULL ) ;
|
|
hWaitingReaders = CreateSemaphore( NULL, 0, LONG_MAX, NULL ) ;
|
|
}
|
|
|
|
CExShareLock::~CExShareLock( ) {
|
|
CloseHandle( hWaitingWriters ) ;
|
|
CloseHandle( hWaitingReaders ) ;
|
|
DeleteCriticalSection( &critWriters ) ;
|
|
}
|
|
|
|
|
|
void
|
|
CExShareLock::ShareLock( ) {
|
|
long sign = InterlockedIncrement( &cReadLock ) ;
|
|
if( sign > 0 ) {
|
|
return ;
|
|
} else {
|
|
// There must be a writer in the lock. Wait for him to leave.
|
|
// The InterlockedIncrement recorded our presence so that the writer
|
|
// can later release the correct number of threads.
|
|
WaitForSingleObject( hWaitingReaders, INFINITE ) ;
|
|
}
|
|
}
|
|
|
|
void
|
|
CExShareLock::ShareUnlock( ) {
|
|
//
|
|
// Leave the lock. The return value will be negative if there is a writer
|
|
// waiting.
|
|
BOOL fWriterWaiting = InterlockedDecrement( &cReadLock ) < 0 ;
|
|
|
|
if( fWriterWaiting ) {
|
|
//
|
|
// The following increment occurs when there is writer waiting, but
|
|
// readers own the lock. So although cReadLock is temporarily inaccurate
|
|
// about the number of readers waiting for the lock, it is not inaccurate
|
|
// when it matters in WriteUnlock (which assumes a writer owns the lock.)
|
|
//
|
|
long junk = InterlockedIncrement( &cReadLock ) ; // restore the value in cReadLock, so that we
|
|
// end up with an accurate count of readers waiting
|
|
// for entry.
|
|
|
|
long sign = InterlockedDecrement( &cOutRdrs ) ; // Make sure we don't lose track of the
|
|
// number for readers who have left the lock.
|
|
//
|
|
// Are we the last reader out of the lock ?
|
|
//
|
|
if( sign == 0 ) {
|
|
//
|
|
// Definately the last reader out !
|
|
//
|
|
ReleaseSemaphore( hWaitingWriters, 1, &junk ) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CExShareLock::ExclusiveLock( ) {
|
|
// Only one writer allowed to try for the lock at a time.
|
|
//
|
|
EnterCriticalSection( &critWriters ) ;
|
|
|
|
//
|
|
// Need to track the number of readers who leave the lock while we
|
|
// are trying to grab it.
|
|
//
|
|
cOutRdrs = 0 ;
|
|
// Grab the lock
|
|
long oldsign = InterlockedExchange( &cReadLock, BlockValue ) ;
|
|
// How many readers left while we grabbed the lock ??
|
|
long oldval = InterlockedExchange( &cOutRdrs, oldsign ) ;
|
|
|
|
//
|
|
// Accurately track all the readers who left the lock.
|
|
//
|
|
long cursign = 1 ; // Initialize to 1 so that if while loop not executed
|
|
// following if statement works correctly.
|
|
while( oldval++ )
|
|
cursign = InterlockedDecrement( &cOutRdrs ) ;
|
|
|
|
//
|
|
// Do we own the lock ? Only if there were no readers, or they have all left already.
|
|
//
|
|
if( oldsign == 0 || cursign == 0 ) {
|
|
// We have the lock
|
|
} else {
|
|
// Wait for a reader to signal us.
|
|
WaitForSingleObject( hWaitingWriters, INFINITE ) ;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CExShareLock::ExclusiveUnlock( ) {
|
|
|
|
// Estimate how many readers are waiting for the lock
|
|
long cWaiting = cReadLock - BlockValue ;
|
|
|
|
// This Exchange allows any readers who have just arrived to grab the lock.
|
|
// Also, it accounts for cWaiting of the blocked readers.
|
|
long cNewWaiting = InterlockedExchange( &cReadLock, cWaiting ) - BlockValue ;
|
|
|
|
// cNewWaiting is the EXACT number of blocked readers - we will increment cReadLock
|
|
// until we have accounted for the difference between our estimate and the correct
|
|
// number !
|
|
long cTotal = cNewWaiting ; // Save cNewWaiting for later use
|
|
while( cNewWaiting-- > cWaiting )
|
|
InterlockedIncrement( &cReadLock ) ;
|
|
|
|
if( cTotal > 0 ) {
|
|
long junk = 0 ;
|
|
ReleaseSemaphore( hWaitingReaders, cTotal, &junk ) ; // let all those readers go!
|
|
}
|
|
// Let the next writer take his shot at the lock!
|
|
LeaveCriticalSection( &critWriters ) ;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CExShareLock::SharedToExclusive( ) {
|
|
|
|
// tbd - implement this!
|
|
return( FALSE ) ;
|
|
}
|
|
|
|
|
|
#endif
|