AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Lock/Unlock-Mechanismus ohne Bezug auf Multithreading?
Thema durchsuchen
Ansicht
Themen-Optionen

Lock/Unlock-Mechanismus ohne Bezug auf Multithreading?

Ein Thema von Der schöne Günther · begonnen am 25. Jul 2019 · letzter Beitrag vom 29. Jul 2019
Antwort Antwort
Seite 1 von 2  1 2      
Der schöne Günther

Registriert seit: 6. Mär 2013
6.115 Beiträge
 
Delphi 10 Seattle Enterprise
 
#1

Lock/Unlock-Mechanismus ohne Bezug auf Multithreading?

  Alt 25. Jul 2019, 12:24
Delphi-Version: 10 Seattle
Ich suche etwas wo man Zugriff auf eine geschützte Resource anfordern kann, und wenn man Zugriff bekommt danach die Sperre wieder frei machen muss.

Alles was ich finde (kritische Abschnitte, Semaphore, Monitor, …) liegt in System oder System.SyncObjs, bezieht sich aber auf Threads. Bei all diesen Implementationen meint er es gut einen Deadlock zu verhindern indem man problemlos sagen kann:

Delphi-Quellcode:
someMutex.Acquire();
someMutex.Acquire();
ShowMessage('Das hier sollte nie zu sehen sein');
Ich suche etwas wo ich sagen kann "TryLock" und er sagt mir "ja/nein". Und dass er mir bitte "Nein" sagt wenn ich im gleichen Thread schon einmal gelocked habe.

Gibt es da etwas in der Standard-Bibliothek? Ich finde nichts.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.090 Beiträge
 
Delphi 12 Athens
 
#2

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

  Alt 25. Jul 2019, 12:44
Das ist jetzt vermutlich zu trivial:
Delphi-Quellcode:
type
  TLock = record
  private
    FLocked: Boolean;
    class function Create: TLock; static;
  public
    function TryLock: Boolean;
    procedure Unlock;
    property Locked: Boolean read FLocked;
  end;

class function TLock.Create: TLock;
begin
  Result.FLocked := False;
end;

function TLock.TryLock: Boolean;
begin
  Result := not FLocked;
  FLocked := True;
end;

procedure TLock.Unlock;
begin
  FLocked := False;
end;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.115 Beiträge
 
Delphi 10 Seattle Enterprise
 
#3

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

  Alt 25. Jul 2019, 12:56
Ja schon ein bisschen 😉
Das ist ja im Endeffekt wie eine globale Boolean-Variable an die jeder dran darf. Ich hätte mir schon vorgestellt dass man es nur unlocken kann wenn man es selbst vorher gelocked hat.

Wenn es nichts gibt bastele ich mir etwas und frage nach Feedback sobald ich fertig bin. Auf die Schnelle kenne ich in den Bibliotheken anderer Sprachen auch nichts...
  Mit Zitat antworten Zitat
Benutzerbild von Neutral General
Neutral General

Registriert seit: 16. Jan 2004
Ort: Bendorf
5.219 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#4

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

  Alt 25. Jul 2019, 13:01
Ich hätte mir schon vorgestellt dass man es nur unlocken kann wenn man es selbst vorher gelocked hat.
Wenn sich alles in einem Thread abspielt ist alles/jeder "man selbst". Wie definierst du dieses "selbst"?
Im Prinzip müsstest du dem Lock() einen (zufälligen?) Wert übergeben den nur die Methode die das Lock() aufgerufen hat lokal kennt und der dann quasi als eine Art "Password" für das Unlock() fungiert.

Also Uwe's Klasse erweitert:
Delphi-Quellcode:
type
  TLock = record
  private
    FLocked: Boolean;
    FPW: Integer;
    class function Create: TLock; static;
  public
    function TryLock(APW: Integer): Boolean;
    function Unlock(APW: Integer): Boolean;
    property Locked: Boolean read FLocked;
  end;

class function TLock.Create: TLock;
begin
  Result.FLocked := False;
end;

function TLock.TryLock(APW: Integer): Boolean;
begin
  Result := not FLocked;
  if (Result) then
  begin
    FLocked := True;
    FPW := APW;
  end;
end;

procedure TLock.Unlock(APW: Integer);
begin
  Result := APW = FPW;
  if Result then
    FLocked := False;
end;
Edit: Uwe's Erweiterung unten ist sogar noch einen Tick eleganter
V
V
Michael
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."

Geändert von Neutral General (25. Jul 2019 um 13:16 Uhr)
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.115 Beiträge
 
Delphi 10 Seattle Enterprise
 
#5

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

  Alt 25. Jul 2019, 13:15
Wenn sich alles in einem Thread abspielt
Das habe ich nicht gesagt. Multithreading-fähig muss das natürlich schon sein.

Im Prinzip müsstest du dem Lock() einen (zufälligen?) Wert übergeben den nur die Methode die das Lock() aufgerufen hat lokal kennt und der dann quasi als eine Art "Password" für das Unlock() fungiert.
Man kann sich natürlich beim Lock auch einen Syhlüssel zum Unlock geben lassen
Richtig, nur dass ich keine GUID oder Integer nehmen würde sondern eine Interface-basierte Referenz die dafür sorgt dass spätestens dann Unlock() gemacht wird wenn man die Referenz wegwirft und man vergessen hat aufzuschließen.


Ich denke im Groben habe ich jetzt auch etwas, das Interface ist ungefähr so:

Delphi-Quellcode:
   ELockException = class(Exception);
   ELockNotHeldException = class(ELockException);

   ILock = interface
   ['{57CCCDE4-63F8-41F6-A6F0-39B4159B06FF}']
      /// <exception cref="ELockNotHeldException" />
      procedure UnLock();
   end;

   ILockableResource = interface
   ['{88085418-BD27-4B5D-AD00-B456C8E017A7}']
      function TryLock(
         out lock: ILock;
         const timeout: TTimeSpan
      ): Boolean; overload;
      function TryLock(out lock: ILock): Boolean; overload;
   end;
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.090 Beiträge
 
Delphi 12 Athens
 
#6

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

  Alt 25. Jul 2019, 13:21
Ich suche etwas wo man Zugriff auf eine geschützte Resource anfordern kann, und wenn man Zugriff bekommt danach die Sperre wieder frei machen muss.
Ich suche etwas wo ich sagen kann "TryLock" und er sagt mir "ja/nein". Und dass er mir bitte "Nein" sagt wenn ich im gleichen Thread schon einmal gelocked habe.
Ich hätte mir schon vorgestellt dass man es nur unlocken kann wenn man es selbst vorher gelocked hat.
Multithreading-fähig muss das natürlich schon sein.
die dafür sorgt dass spätestens dann Unlock() gemacht wird wenn man die Referenz wegwirft und man vergessen hat aufzuschließen.
Deine Spezifikationen vermehren sich mit jedem Post
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.090 Beiträge
 
Delphi 12 Athens
 
#7

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

  Alt 25. Jul 2019, 13:12
dass man es nur unlocken kann wenn man es selbst vorher gelocked hat.
Wer ist denn selbst bzw. wie identifiziert sich dieses selbst? Man kann sich natürlich beim Lock auch einen Syhlüssel zum Unlock geben lassen:
Delphi-Quellcode:
  TLock = record
  private
    FLocked: TGUID;
    class function Create: TLock; static;
    function GetLocked: Boolean;
  public
    function TryLock(var Key: TGUID): Boolean;
    function Unlock(const Key: TGUID): Boolean;
    property Locked: Boolean read GetLocked;
  end;

class function TLock.Create: TLock;
begin
  Result.FLocked := TGUID.Empty;
end;

function TLock.GetLocked: Boolean;
begin
  Result := (FLocked <> TGUID.Empty);
end;

function TLock.Unlock(const Key: TGUID): Boolean;
begin
  Result := False;
  if Key = FLocked then begin
    FLocked := TGUID.Empty;
    Result := True;
  end;
end;

function TLock.TryLock(var Key: TGUID): Boolean;
begin
  Result := False;
  if not Locked then begin
    Key := TGUID.NewGuid;
    FLocked := Key;
    Result := True;
  end;
end;
Das scheint aber schon eine sehr spezielle Anforderung zu sein, die du da umsetzen willst.

Ich sehe gerade, da hat das schon jemand aufgegriffen.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.090 Beiträge
 
Delphi 12 Athens
 
#8

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

  Alt 26. Jul 2019, 11:12
Bist du sicher, daß der Code auch diese Forderung abdeckt?
Und dass er mir bitte "Nein" sagt wenn ich im gleichen Thread schon einmal gelocked habe.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.115 Beiträge
 
Delphi 10 Seattle Enterprise
 
#9

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

  Alt 26. Jul 2019, 12:13
Vielen Dank für die Mühe.

Ich habe Angst vor dem Gepointere - Du fütterst TMonitor mit einem von außen übergebenen Pointer, der erwartet aber TObject. Ich hätte spontan eine Interface-Referenz reingesteckt ☠

Ich zeige mal was ich draus gemacht habe:

Definition, Implementation & Tests @ Gist.Github.com

Im Endeffekt ist es das hier:

Delphi-Quellcode:
type
   ILockableResourceControl = interface
   ['{21971BDB-F68E-483E-9324-0CA924EE14CE}']
      procedure UnRegisterLock(const lock: ILock);
   end;

   TLockableResource = class(TInterfacedObject, ILockableResource, ILockableResourceControl)
      private type
         /// <summary>
         /// Use raw pointers to circumvent reference counting
         /// </summary>
         {$If CompilerVersion >= 31}{$Message 'Consider [Weak] attribute'}{$EndIf}
         PLock = ^ILock;
      private var
         mutex: TCriticalSection;
         currentLockPointer: PLock;
         lockAvailableEvent: TEvent;
      protected
         function getCurrentLock(): ILock;
      public
         constructor Create();
         destructor Destroy(); override;
         procedure UnregisterLock(const lock: ILock);
         function TryLock(out lock: ILock): Boolean; overload;
         function TryLock(out lock: ILock; const timeout: TTimeSpan): Boolean; overload;
   end;
sowie

Delphi-Quellcode:
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;
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
3.937 Beiträge
 
Delphi 12 Athens
 
#10

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

  Alt 27. Jul 2019, 14:53
Warum nennst Du die CS mutex ?
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:31 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz