Delphi-PRAXiS
Seite 2 von 4     12 34      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Ringpuffer Bibliothek veröffentlicht (https://www.delphipraxis.net/205297-ringpuffer-bibliothek-veroeffentlicht.html)

Rollo62 3. Jan 2022 16:06

AW: Ringpuffer Bibliothek veröffentlicht
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1499973)
Dafür würde ich eine eigene Klasse mit separater Implementierung empfehlen. Ich fände es kontraproduktiv, wenn man die wohl unvermeidlichen Performance-Nachteile auch immer für den non-thread Bereich mitschleppen müsste.

Ja an sowas dachte ich eigentlich auch, nur eben auf Basis des TRingBuffer's.
Deshalb frage ich ja ob da schon sowas geplant ist und womöglich kommen wird, oder eher nicht.

Zitat:

Zitat von TurboMagic (Beitrag 1499977)
was wäre, wenn man in die Ringpuffer Klasse so wie sie jetzt ist,
je eine Enter und Leave (Exit als Name würde ich wegen dem Keyword
Exit eher nicht bevorzugen) Methode einbaut,

Zitat:

Zitat von himitsu (Beitrag 1499976)
[DELPHI]Buffer.Enter;
Buffer.Add(irgendwas);
Buffer.Exit;


type
TRingbuffer<T> = class(Ringbuffer.TRingbuffer<T>)
procedure Enter;
procedure Exit;
end;

Ja sowas ginge auch.
Ich dachte aber eher an eine Klasse die implizit threadsafe ist,
also z.B. TRingbuffer<T> und TRingbuffer_Safe<T>

So dass man die Klasse ohne Änderung beim Aufrufer 1:1 tauschen könnte.

Das separate Enter/Exit hat natürlich auch seine Vorzüge, einer granulareren Steuerung,
wenn man das in vielen unterschiedlichen Szenarien einsetzen würde.
Eigentlich möchte ich nur die laufenden Basic's Push/Pop/Length usw. absichern,
um bedenkenlos Lesen/Schreiben zu können, das wäre doch sehr gut integrierbar.

Welche Vorteile hätte ich denn sonst noch von einem externen, separatem Enter/Exit ?
Da sehe ich eher die Gefahr mal ein Enter/Exit zu vergessen.

Das ist wohl wieder so eine Philosophie-Frage, wo es am Ende zwei Lager gibt :stupid:
Oder gibt es da einen klaren, technischen Favoriten ?

himitsu 3. Jan 2022 16:44

AW: Ringpuffer Bibliothek veröffentlicht
 
Historisch hab ich sonst ein Leave statt Exit (Exit hier, weil's in TMonitor so heißt)


Implizit ... joar, ich war schreibfaul ... statt du überall vor Ort zu machen,
kann man auch in der Ableitung die Methoden ala Add usw. überdecken/überschreiben und dort das Enter/Exit/Leave rein tun.

Überschreiben (virtual+override) ist besser, falls man zwar die TRingbuffer_Safe<> verwendet, aber die Variable auf TRingbuffer<> stehen bleibt.



Der Vorteil am "Externen" ist, dass man es für ALLE Klassen verwenden kann, ohne Diese erst anpassen zu müssen.



TMonitor hat den Vorteil, dass es multiplatform ist (CriticalSection ist ja Windows) und dass es angeblich schneller sein soll.
Aber der wirkliche Vorteil ist, dass man keine Variable dafür braucht. (OK, die braucht es immernoch, aber sie ist bereits in allen TObject-Nachfahren integriert)

TurboMagic 3. Jan 2022 16:47

AW: Ringpuffer Bibliothek veröffentlicht
 
Hallo,

ich hab' ja noch keine Antworten auf meine Idee mit den leeren überschreibbaren Methoden bekommen.
Falls das aber ein geeigneter Ansatz wäre eine intrinsische Variante (die ich auch bevorzugen möchte)
umzusetzen darfst du das gerne einbringen! Mache einen entsprechenden Pull Request oder schicke mir
die Unit anderweitig zu.

Wichtig ist halt, dass alle existierenden Unit Tests bestanden werden. Die Frage für mich wäre auch,
wie man Multithreaded Code Unit testen kann...

=> Würde mich über deinen Beitrag dazu sehr freuen!

Grüße
TurboMagic

himitsu 3. Jan 2022 16:52

AW: Ringpuffer Bibliothek veröffentlicht
 
siehe mein Edit?


Alles Testen ist schwer.
Explizit einige bestimmte Sperrszenarien kann man als Test aufbauen,
aber prüfen, ob eine Funktion per se threadsave ist, kann nicht getestet werden, außer man führt es milliardenmal mit unterschiedlichen Timings/Auslastungen aus und hofft man trifft zufällig eine problematische Überschneidung.

TurboMagic 3. Jan 2022 16:59

AW: Ringpuffer Bibliothek veröffentlicht
 
Sorry, habe ich noch nicht wirklich gesehen.
Bin gedanklich gerade bei der Übernahme von Code für die DEC
(siehe anderen Post von mir von eben).

TurboMagic 3. Jan 2022 17:03

AW: Ringpuffer Bibliothek veröffentlicht
 
Zitat:

Zitat von himitsu (Beitrag 1499982)
Implizit ... joar, ich war schreibfaul ... statt du überall vor Ort zu machen,
kann man auch in der Ableitung die Methoden ala Add usw. überdecken/überschreiben und dort das Enter/Exit/Leave rein tun.

Überschreiben (virtual+override) ist besser, falls man zwar die TRingbuffer_Safe<> verwendet, aber die Variable auf TRingbuffer<> stehen bleibt.

Der Vorteil am "Externen" ist, dass man es für ALLE Klassen verwenden kann, ohne Diese erst anpassen zu müssen.

TMonitor hat den Vorteil, dass es multiplatform ist (CriticalSection ist ja Windows) und dass es angeblich schneller sein soll.
Aber der wirkliche Vorteil ist, dass man keine Variable dafür braucht. (OK, die braucht es immernoch, aber sie ist bereits in allen TObject-Nachfahren integriert)

Die Frage ist, was besser ist: meine Idee das schon als Konzept in die Basisklasse einzubauen diese Methoden aber leer
zu lassen (ist der Compiler schlau genug das bei Nutzung der Basisklasse als "nop" zu erkennen und somit auszulassen?)
oder alle public Methoden als Virtual zu deklarieren und in der abgeleiteten Klasse zu überschreiben? Wie sieht es mit
dem XMLDOC aus? Muss man den in der abgeleiteten Klasse duplizieren damit er funktioniert?

Grüße
TurboMagic

TurboMagic 3. Jan 2022 17:08

AW: Ringpuffer Bibliothek veröffentlicht
 
Zitat:

Zitat von Rollo62 (Beitrag 1499980)
Zitat:

Zitat von Uwe Raabe (Beitrag 1499973)
Dafür würde ich eine eigene Klasse mit separater Implementierung empfehlen. Ich fände es kontraproduktiv, wenn man die wohl unvermeidlichen Performance-Nachteile auch immer für den non-thread Bereich mitschleppen müsste.

Ja an sowas dachte ich eigentlich auch, nur eben auf Basis des TRingBuffer's.
Deshalb frage ich ja ob da schon sowas geplant ist und womöglich kommen wird, oder eher nicht.

Es wird vor allem dann kommen, wenn du's beisteuerst ;-)
Wäre aber natürlich gut, wenn wir hier vorher möglichst einen klaren Architekturfavoritän küren könnten ;-)

Grüße
TurboMagic

mytbo 3. Jan 2022 17:11

AW: Ringpuffer Bibliothek veröffentlicht
 
Zitat:

Zitat von Rollo62 (Beitrag 1499972)
Ich benutze RingBuffer um Input/Output Ströme zu entkoppeln, die dann mit unterschiedlichen, variablen Datenraten abgearbeitet werden.
Da wäre threadsafety-ness recht praktisch.

Vielleicht TSynQueue aus der mORMot Unit mormot.core.threads.
Delphi-Quellcode:
var
  FInOutStream: TSynQueue;
begin
  FInOutStream := TSynQueue.Create(TypeInfo(TRawByteStringDynArray));
...
Bis bald...
Thomas

TurboMagic 3. Jan 2022 17:17

AW: Ringpuffer Bibliothek veröffentlicht
 
Vielleicht, nur zieht man sich damit nicht jede Menge andere Dinge aus mormot mit rein?
Die Ringpuffer Umsetzung die angesprochen war hat den Charme, dass es eine einzelne Unit ist.

Uwe Raabe 3. Jan 2022 17:19

AW: Ringpuffer Bibliothek veröffentlicht
 
Jetzt alle relevanten Methoden in Enter/Leave zu klammern halte ich für wenig hilfreich, denn das sind in non-threadsafe Fall immer zwei überflüssige Calls. Davon abgesehen wird das in einigen Fällen auch nicht reichen, z.B. wenn man erwartet, dass ein Peek gefolgt von einem Pop ein konsistentes Ergebnis liefert. Aber auch das property Notify ist mit dem direkten Feldzugriff nicht wirklich threadsicher.

Delphi-Quellcode:
TRingBuffer
in einer thread-safe Version ableiten läuft konträr zur aktuellen Ableitungsphilosophie mit
Delphi-Quellcode:
TObjectRingbuffer
. Man müsste dann womöglich jede Ableitung in zwei Flavors machen:
TRingbuffer<T> -> TThreadsafeRingBuffer<T>
TObjectRingbuffer<T:class> -> TThreadsafeObjectRingbuffer<T:class>
Das erscheint mir nicht sonderlich sinnvoll.

Ein möglicher Ansatz, der den ursprünglichen Ringbuffer unangetastet lässt, wäre ein Wrapper für den Zugriff - analog zu
Delphi-Quellcode:
TThreadList
:
Delphi-Quellcode:
type
  TThreadRingBufferWrapper<T> = class
  private
    FLock: TObject;
    FRingBuffer: TRingBuffer<T>;
  public
    constructor Create(ARingBuffer: TRingBuffer<T>);
    destructor Destroy; override;
    function LockBuffer: TRingBuffer<T>;
    procedure UnlockBuffer; inline;
  end;

...

constructor TThreadRingBufferWrapper<T>.Create(ARingBuffer: TRingBuffer<T>);
begin
  inherited Create;
  FRingBuffer := ARingBuffer;
  FLock := TObject.Create();
end;

destructor TThreadRingBufferWrapper<T>.Destroy;
begin
  LockBuffer;
  try
    FRingBuffer.Free;
    inherited Destroy;
  finally
    UnlockBuffer;
    FLock.Free;
  end;
end;

function TThreadRingBufferWrapper<T>.LockBuffer: TRingBuffer<T>;
begin
  TMonitor.Enter(FLock);
  Result := FRingBuffer;
end;

procedure TThreadRingBufferWrapper<T>.UnlockBuffer;
begin
  TMonitor.Exit(FLock);
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:13 Uhr.
Seite 2 von 4     12 34      

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz