unit SimpleSync;

{ Martin Harvey 27/5/2000 }

interface

uses Windows;

type
  TSimpleSynchronizer = class(TObject)
  private
    FDataLock, FWriteLock: TRTLCriticalSection;
    FActRead, FReadRead, FActWrite, FWriteWrite: integer;
    FReaderSem, FWriterSem: THandle;
  protected
  public
    constructor Create;
    destructor Destroy; override;
    procedure StartRead;
    procedure StartWrite;
    procedure EndRead;
    procedure EndWrite;
  published
  end;

implementation

constructor TSimpleSynchronizer.Create;
begin
  inherited Create;
  InitializeCriticalSection(FDataLock);
  InitializeCriticalSection(FWriteLock);
  FReaderSem := CreateSemaphore(nil, 0, High(Integer), nil);
  FWriterSem := CreateSemaphore(nil, 0, High(Integer), nil);
  { Initial values of 0 OK for all counts }
end;

destructor TSimpleSynchronizer.Destroy;
begin
  DeleteCriticalSection(FDataLock);
  DeleteCriticalSection(FWriteLock);
  CloseHandle(FReaderSem);
  CloseHandle(FWriterSem);
  inherited Destroy;
end;

procedure TSimpleSynchronizer.StartRead;
begin
  EnterCriticalSection(FDataLock);
  Inc(FActRead);
  if FActWrite = 0 then
  begin
    Inc(FReadRead);
    ReleaseSemaphore(FReaderSem, 1, nil);
  end;
  LeaveCriticalSection(FDataLock);
  WaitForSingleObject(FReaderSem, INFINITE);
end;

procedure TSimpleSynchronizer.StartWrite;
begin
  EnterCriticalSection(FDataLock);
  Inc(FActWrite);
  if FReadRead = 0 then
  begin
    Inc(FWriteWrite);
    ReleaseSemaphore(FWriterSem, 1, nil);
  end;
  LeaveCriticalSection(FDataLock);
  WaitForSingleObject(FWriterSem, INFINITE);
  EnterCriticalSection(FWriteLock);
end;

procedure TSimpleSynchronizer.EndRead;
begin
  EnterCriticalSection(FDataLock);
  Dec(FReadRead);
  Dec(FActRead);
  if FReadRead = 0 then
  begin
    while FWriteWrite < FActWrite do
    begin
      Inc(FWriteWrite);
      ReleaseSemaphore(FWriterSem, 1, nil);
    end;
  end;
  LeaveCriticalSection(FDataLock);
end;

procedure TSimpleSynchronizer.EndWrite;
begin
  LeaveCriticalSection(FWriteLock);
  EnterCriticalSection(FDataLock);
  Dec(FWriteWrite);
  Dec(FActWrite);
  if FActWrite = 0 then
  begin
    while FReadRead < FActRead do
    begin
      Inc(FReadRead);
      ReleaseSemaphore(FReaderSem, 1, nil);
    end;
  end;
  LeaveCriticalSection(FDataLock);
end;

end.