unit EventSync;
{ Martin Harvey 5/6/2000 }
interface
uses Windows;
type
 TEventSynchronizer = class(TObject)
 private
 FDataLock, FWriteLock: TRTLCriticalSection;
 FReaders, FWriters: integer;
 FNoReaders, FNoWriters: THandle;
 protected
 public
 constructor Create;
 destructor Destroy; override;
 procedure StartRead;
 procedure StartWrite;
 procedure EndRead;
 procedure EndWrite;
 published
 end;
implementation
constructor TEventSynchronizer.Create;
begin
 inherited Create;
 InitializeCriticalSection(FDataLock);
 InitializeCriticalSection(FWriteLock);
 FNoReaders := CreateEvent(nil, true, true, nil);
 FNoWriters := CreateEvent(nil, true, true, nil);
end;
destructor TEventSynchronizer.Destroy;
begin
 DeleteCriticalSection(FDataLock);
 DeleteCriticalSection(FWriteLock);
 CloseHandle(FNoReaders);
 CloseHandle(FNoWriters);
 inherited Destroy;
end;
 
procedure TEventSynchronizer.StartRead;
 
var
 Block: boolean;
 
begin
 EnterCriticalSection(FDatalock);
 if FReaders = 0 then
 ResetEvent(FNoReaders);
 Inc(FReaders);
 Block := FWriters > 0;
 LeaveCriticalSection(FDataLock);
 if Block then
 WaitForSingleObject(FNoWriters, INFINITE);
end;
 
procedure TEventSynchronizer.StartWrite;
 
var
 Block: boolean;
 
begin
 EnterCriticalSection(FDataLock);
 if FWriters = 0 then
 ResetEvent(FNoWriters);
 Inc(FWriters);
 Block := FReaders > 0;
 LeaveCriticalSection(FDataLock);
 if Block then
 WaitForSingleObject(FNoReaders, INFINITE);
 EnterCriticalSection(FWriteLock);
end;
 
procedure TEventSynchronizer.EndRead;
begin
 EnterCriticalSection(FDataLock);
 Dec(FReaders);
 if FReaders = 0 then
 SetEvent(FNoReaders);
 LeaveCriticalSection(FDataLock);
end;
 
procedure TEventSynchronizer.EndWrite;
begin
 LeaveCriticalSection(FWriteLock);
 EnterCriticalSection(FDataLock);
 Dec(FWriters);
 if FWriters = 0 then
 SetEvent(FNoWriters);
 LeaveCriticalSection(FDataLock);
end;
end.