Einzelnen Beitrag anzeigen

TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.058 Beiträge
 
Delphi 10.4 Sydney
 
#12

AW: Lock/Unlock-Mechanismus ohne Bezug auf Multithreading?

  Alt 26. Jul 2019, 12:05
Delphi-Quellcode:
program LockWithInstance;

{$APPTYPE CONSOLE}

{$R *.res}

uses
    System.SysUtils,
    System.Timespan,
    System.SyncObjs;

type
    ELockException = class(Exception);
    ELockNotHeldException = class(ELockException);
    TInstance = Pointer;

    ILock = interface
        ['{57CCCDE4-63F8-41F6-A6F0-39B4159B06FF}']
        function Lock(const AInstance: TInstance; ATimeout: Cardinal = 0): Boolean;
        /// <exception cref="ELockNotHeldException" />
        procedure UnLock(const AInstance: TInstance);
    end;

    ILockableResource = interface
        ['{88085418-BD27-4B5D-AD00-B456C8E017A7}']
        function TryLock(
          const AInstance: TInstance;
          out lock: ILock;
          const timeout: TTimeSpan
          ): Boolean; overload;
        function TryLock(const AInstance: TInstance; out lock: ILock): Boolean; overload;
    end;

    TLock = class(TInterfacedObject, ILock)
    strict private
        FInstance: TInstance;
    public
        constructor Create;
        function Lock(const AInstance: TInstance; ATimeout: Cardinal = 0): Boolean;
        procedure UnLock(const AInstance: TInstance);

    end;

    TLockableResource = class(TInterfacedObject, ILockableResource)
    strict private
        FLock: ILock;
    public
        constructor Create();
        function TryLock(
          const AInstance: TInstance;
          out lock: ILock;
          const timeout: TTimeSpan
          ): Boolean; overload;
        function TryLock(const AInstance: TInstance; out lock: ILock): Boolean; overload;
    end;

constructor TLock.Create;
begin
    inherited Create;
end;

function TLock.Lock(const AInstance: TInstance; ATimeout: Cardinal = 0): Boolean;
begin
    if FInstance = nil then
    begin
        FInstance := AInstance;
        Result := TMonitor.Enter(FInstance, ATimeout);
    end
    else
        raise ELockException.Create('This is a different instance!');
end;

procedure TLock.UnLock(const AInstance: TInstance);
begin
    if AInstance = FInstance then
    begin
        TMonitor.Exit(AInstance);
    end
    else
        raise ELockNotHeldException.Create('This instance is not holding the lock!');

end;

{ TLockableResource }

function TLockableResource.TryLock(const AInstance: TInstance; out lock: ILock; const timeout: TTimeSpan): Boolean;
begin
    lock := FLock;
    Result := lock.Lock(AInstance);
end;

constructor TLockableResource.Create;
begin
    FLock := TLock.Create
end;

function TLockableResource.TryLock(const AInstance: TInstance; out lock: ILock): Boolean;
begin
    lock := FLock;
    Result := lock.Lock(AInstance);
end;

procedure Test1;
var
    A, B: TObject;
    LockableResource: ILockableResource;
    Lock: ILock;
begin
    A := TObject.Create;
    B := TObject.Create;
    LockableResource := TLockableResource.Create;

    LockableResource.TryLock(A, Lock);
    Lock.unlock(B);
    LockableResource.TryLock(B, Lock);

    B.Free;
    A.Free;
end;

procedure Test2;
var
    A, B: TObject;
    LockableResource: ILockableResource;
    Lock: ILock;
begin
    A := TObject.Create;
    B := TObject.Create;
    LockableResource := TLockableResource.Create;

    LockableResource.TryLock(A, Lock);
    LockableResource.TryLock(B, Lock);

    B.Free;
    A.Free;
end;

begin
    try
        Test1;
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;

    try
        Test2;
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
    Readln;

end.
So!
  Mit Zitat antworten Zitat