You've already forked lazarus-ccr
100 lines
1.9 KiB
ObjectPascal
100 lines
1.9 KiB
ObjectPascal
![]() |
unit semaphore;
|
||
|
|
||
|
{$mode objfpc}{$H+}
|
||
|
interface
|
||
|
|
||
|
uses
|
||
|
Classes, SysUtils, syncobjs;
|
||
|
|
||
|
type
|
||
|
|
||
|
ESemaphoreException = class(Exception);
|
||
|
|
||
|
{ TSemaphoreObject }
|
||
|
|
||
|
TSemaphoreObject = class
|
||
|
private
|
||
|
FHandle : PRTLEvent;
|
||
|
FLimit: Integer;
|
||
|
FCurrentState : Integer;
|
||
|
FCriticalSection : TCriticalSection;
|
||
|
public
|
||
|
constructor Create(const ALimit : Integer);
|
||
|
destructor Destroy(); override;
|
||
|
function WaitFor(ATimeout : Cardinal) : TWaitResult;
|
||
|
procedure Release();
|
||
|
property Limit : Integer read FLimit;
|
||
|
end;
|
||
|
|
||
|
implementation
|
||
|
|
||
|
{ TSemaphoreObject }
|
||
|
|
||
|
constructor TSemaphoreObject.Create(const ALimit: Integer);
|
||
|
begin
|
||
|
Assert(ALimit>0);
|
||
|
FLimit := ALimit;
|
||
|
FHandle := RTLEventCreate();
|
||
|
FCriticalSection := TCriticalSection.Create();
|
||
|
FCurrentState := FLimit;
|
||
|
RTLeventSetEvent(FHandle);
|
||
|
end;
|
||
|
|
||
|
destructor TSemaphoreObject.Destroy();
|
||
|
begin
|
||
|
RTLeventdestroy(FHandle);
|
||
|
FreeAndNil(FCriticalSection);
|
||
|
inherited Destroy();
|
||
|
end;
|
||
|
|
||
|
function TSemaphoreObject.WaitFor(ATimeout: Cardinal): TWaitResult;
|
||
|
var
|
||
|
ok : Boolean;
|
||
|
begin
|
||
|
Result := wrTimeout;
|
||
|
ok := False;
|
||
|
FCriticalSection.Acquire();
|
||
|
try
|
||
|
if ( FCurrentState > 0 ) then begin
|
||
|
Dec(FCurrentState);
|
||
|
ok := True;
|
||
|
if ( FCurrentState = 0 ) then
|
||
|
RTLeventResetEvent(FHandle);
|
||
|
end;
|
||
|
finally
|
||
|
FCriticalSection.Release();
|
||
|
end;
|
||
|
if not ok then begin
|
||
|
RTLeventWaitFor(FHandle,ATimeout);
|
||
|
FCriticalSection.Acquire();
|
||
|
try
|
||
|
if ( FCurrentState > 0 ) then begin
|
||
|
Dec(FCurrentState);
|
||
|
ok := True;
|
||
|
end;
|
||
|
finally
|
||
|
FCriticalSection.Release();
|
||
|
end;
|
||
|
end;
|
||
|
if ok then
|
||
|
Result := wrSignaled;
|
||
|
end;
|
||
|
|
||
|
procedure TSemaphoreObject.Release();
|
||
|
begin
|
||
|
FCriticalSection.Acquire();
|
||
|
try
|
||
|
if ( FCurrentState < Limit ) then begin
|
||
|
Inc(FCurrentState);
|
||
|
end else begin
|
||
|
raise ESemaphoreException.Create('Invalid semaphore operation.');
|
||
|
end;
|
||
|
finally
|
||
|
FCriticalSection.Release();
|
||
|
end;
|
||
|
RTLeventSetEvent(FHandle);
|
||
|
end;
|
||
|
|
||
|
end.
|
||
|
|