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);
 { El valor inicial 0 est bien para todos los contadores }
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.