implementation uses
System.SysUtils,
System.Classes,
System.Threading;
{ TLockableResource }
constructor TLockableResource.Create();
begin
inherited Create();
mutex := TCriticalSection.Create();
lockAvailableEvent := TSimpleEvent.Create();
end;
destructor TLockableResource.Destroy();
begin
mutex.Acquire();
if Assigned(getCurrentLock())
then
getCurrentLock().UnLock();
lockAvailableEvent.Free();
mutex.Free();
inherited;
end;
function TLockableResource.getCurrentLock(): ILock;
begin
Result := ILock(currentLockPointer);
end;
function TLockableResource.TryLock(
out lock: ILock): Boolean;
begin
mutex.Acquire();
try
if Assigned(getCurrentLock())
then
Result := False
else
begin
lock := TLock.Create(self);
currentLockPointer := PLock(lock);
Result := True;
end;
finally
mutex.Release();
end;
end;
function TLockableResource.tryLock(
out lock: ILock;
const timeout: TTimeSpan): Boolean;
var
future: IFuture<ILock>;
begin
future := TTask.Future<ILock>(
function(): ILock
begin
while not TryLock(Result)
do
begin
lockAvailableEvent.WaitFor();
TTask.CurrentTask().CheckCanceled();
end;
end
);
Result := future.Wait(timeout);
if Result
then
lock := future.Value
else
future.Cancel();
end;
procedure TLockableResource.UnregisterLock(
const lock: ILock);
begin
mutex.Acquire();
try
if (lock <> getCurrentLock())
then
raise ELockException.Create(
String.Empty);
currentLockPointer :=
nil;
lockAvailableEvent.SetEvent();
finally
mutex.Release();
end;
end;