Delphi-PRAXiS

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)

TurboMagic 23. Aug 2020 11:18

Ringpuffer Bibliothek veröffentlicht
 
Hallo,

ich habe soeben eine Bibliothek die ich mal geschrieben hatte als OpenSource auf Github veröffentlicht.
Es ist eine generische Ringpufferumsetzung, also ein Ringpuffer den man problemlos für nicht verwaltete
Datentypen wie Bytes, Integer, Double usw. aber auch für Klassen wie TMyWorkItem usw. nutzen kann.

Das Projekt beinhaltet auch DUnit Tests, wobei sich diese nicht so gut in der IDE ausführen lassen, da
auch geworfene Exceptions getestet werden.

Das Projekt befindet sich hier:
https://github.com/MHumm/CircularBuffer

Es wurde ursprünglich in XE8 begonnen, läuft auch in 10.4 und vermutlich auch in älteren Versionen,
wobei deren Nutzer ruhig mal an ein Update denken dürfen ;-)

Wer was zum Projekt beitragen möchte gerne: z.B. fehlen noch ein paar Unit Tests (man sieht welche
noch leer sind) oder die Kommentare (und damit meine ich auch XMLDOC!) sind noch alle auf Deutsch.

Grüße
TurboMagic

Uwe Raabe 23. Aug 2020 13:00

AW: Ringpuffer Bibliothek veröffentlicht
 
Warum ist
Delphi-Quellcode:
TRingbuffer<T>.Create
overload?

TurboMagic 23. Aug 2020 15:59

AW: Ringpuffer Bibliothek veröffentlicht
 
Hallo Uwe,

das weiß ich gerade nicht mehr. Gibt's evtl. verschiedene Konstruktoren?
Kannst aber gerne einen Pull Request einreichen. Dann muss ich aber erst
lernen wie man die in Git/Github bearbeitet.

Grüße
TurboMagic

Uwe Raabe 23. Aug 2020 16:19

AW: Ringpuffer Bibliothek veröffentlicht
 
Bin gerade dabei die XMLDOC zu übersetzen...

TurboMagic 23. Aug 2020 16:27

AW: Ringpuffer Bibliothek veröffentlicht
 
Cool!

Rollo62 3. Jan 2022 14:44

AW: Ringpuffer Bibliothek veröffentlicht
 
Der Thread ist schon etwas älter, aber hatte ich ganz aus den Augen verloren,
und bin gerade durch GetIt nochmal draufgestossen worden dass es den RingBuffer gibt.

Soweit ich das sehe ist dieser nicht threadsafe.
Gibt es da Bestrebungen das mal in diese Richtung zu erweitern ?

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.

Uwe Raabe 3. Jan 2022 15:13

AW: Ringpuffer Bibliothek veröffentlicht
 
Zitat:

Zitat von Rollo62 (Beitrag 1499972)
Soweit ich das sehe ist dieser nicht threadsafe.
Gibt es da Bestrebungen das mal in diese Richtung zu erweitern ?

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.

TurboMagic 3. Jan 2022 16:31

AW: Ringpuffer Bibliothek veröffentlicht
 
Hallo

der ist vermutlich nicht Thread sicher, jedenfalls war das damals kein Design Ziel.
Was auch noch damit ist: er erlaubt es auch nicht, dass Daten die noch nicht abgerufen
wurden überschrieben werden können.

Sprich: wenn er voll ist un du weitere Daten hinzufügen willst gibt's eine Exception.

Es gab' mal die Überlegung, dafür ein Flag einzubauen und die Klasse so zu erweitern,
dass das wahlweise auch geht, da ich das aber gerade nicht ernsthaft brauche, hab' ich
das noch nicht umgesetzt. Arbeite gerade an anderen Projekten...
...bin aber für Beiträge in diese Richtung und auch in RIchtung einer abgeleiteten Klasse
die Threadsicherheit hinzufügt offen! Lohn ist natürlich die Erwähnung in den Credits! ;-)

Grüße
TurboMagic

himitsu 3. Jan 2022 16:35

AW: Ringpuffer Bibliothek veröffentlicht
 
Es ist dir ja nicht verboten eine CriticalSection, oder sonstwas hinzuzufügen.

Delphi-Quellcode:
System.TMonitor.Enter(Buffer);
Buffer.Add(irgendwas);
System.TMonitor.Exit(Buffer);

Delphi-Quellcode:
Buffer.Enter;
Buffer.Add(irgendwas);
Buffer.Exit;


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

procedure TRingbuffer<T>.Enter;
begin
  System.TMonitor.Enter(Self);
end;
Und vielleicht kommt ja Emba irgendwann in diesem Jahrhundert mal auf die Idee den Schwachsinn bei TMonitor zu reparieren.
> doppelter/missverständlicher Name und umständliche Nutzung (Wenn das eh in TObjekt integriert ist, dann doch bitte richtig)

TurboMagic 3. Jan 2022 16:41

AW: Ringpuffer Bibliothek veröffentlicht
 
Hallo,

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, die virtuell, leer und
inline ist aber an allen relevanten Stellen aufgerufen wird.

Wer dann eine Threadsichere Variante will, braucht nur noch von der
bisherigen ableiten und Enter und Leave passend überschreiben.

Wie wäre das?

Grüße
Turbo Magic

Rollo62 3. Jan 2022 17: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 17: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 17: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 17: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 17: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 18: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 18: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 18: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 18: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 18: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;

TurboMagic 3. Jan 2022 18:28

AW: Ringpuffer Bibliothek veröffentlicht
 
Hallo,

die Idee ist glaube ich gar nicht so schlecht!
Wenn die anderen diese auch als sinnvoll ansehen muss die nur noch jemand
offiziell einspeisen... ;-)

Am besten mit den Unit Tests die man, trotz der Schwierigkeiten Multithreaded
Code Unit getestet zu bekommen, umsetzen kann gleich beigesteuert. Am besten in
einer neuen Unit Test Klasse/Fixture...

Grüße
TurboMagic

Rollo62 3. Jan 2022 18:55

AW: Ringpuffer Bibliothek veröffentlicht
 
Zitat:

Zitat von himitsu (Beitrag 1499982)
TMonitor hat den Vorteil, dass es multiplatform ist (CriticalSection ist ja Windows) und dass es angeblich schneller sein soll.

<OT>
Schneller, einfacher: OK, aber wieso sollte TCriticalSection nicht multiplattform sein ?
https://docwiki.embarcadero.com/Libr...riticalSection

Für asymmetrische Pushs/Pops Szenarios böte sich da auch noch TLightweightMREW an.

</OT>

Uwe Raabe 3. Jan 2022 18:57

AW: Ringpuffer Bibliothek veröffentlicht
 
Ich habe das nochmal etwas verallgemeinert, da der Wrapper ja gar nichts über die zu wrappende Instanz wissen muss. Damit kann das als Wrapper für quasi jede Objekt-Instanz herhalten und man bekommt über LockInstance auch gleich den tatsachlich übergebenen Typ zurück mit allen dort verfügbaren Methoden und Eigenschaften.
Delphi-Quellcode:
type
  TThreadWrapper<T: class> = class
  private
    FLock: TObject;
    FInstance: T;
    FOwnsInstance: Boolean;
  public
    constructor Create(AInstance: T; AOwnsInstance: Boolean = True);
    destructor Destroy; override;
    function LockInstance: T;
    procedure UnlockInstance; inline;
    property OwnsInstance: Boolean read FOwnsInstance write FOwnsInstance;
  end;

...

constructor TThreadWrapper<T>.Create(AInstance: T; AOwnsInstance: Boolean = True);
begin
  inherited Create;
  FInstance := AInstance;
  FLock := TObject.Create();
  FOwnsInstance := AOwnsInstance;
end;

destructor TThreadWrapper<T>.Destroy;
begin
  LockInstance;
  try
    if OwnsInstance then
      FInstance.Free;
    FInstance := nil;
    inherited Destroy;
  finally
    UnlockInstance;
    FLock.Free;
  end;
end;

function TThreadWrapper<T>.LockInstance: T;
begin
  TMonitor.Enter(FLock);
  Result := FInstance;
end;

procedure TThreadWrapper<T>.UnlockInstance;
begin
  TMonitor.Exit(FLock);
end;

himitsu 3. Jan 2022 18:59

AW: Ringpuffer Bibliothek veröffentlicht
 
Jupp, einige Methoden/Property kann man nicht Thread-safe machen.

Außer man lässt solch problematischen Methoden weg. Und falls man sie dennoch benötigt, dann in einer SubKlasse (ala LockBuffer) verstecken,
oder in diesen Methoden/Property eine Exception werfen, wenn vorher extern kein Enter/Lock gestartet wurde.

Die komplette Klasse muß man da nicht wegsperren, um die einachen Sachen weiterhin einfach/direkt aufrufen zu können.



Wenn FInstance immer keine Klasse ist, dann kannst statt FLock auch direkt FInstance verwenden, oder den TThreadWrapper selbst.

Uwe Raabe 3. Jan 2022 18:59

AW: Ringpuffer Bibliothek veröffentlicht
 
Zitat:

Zitat von Rollo62 (Beitrag 1500006)
Für asymmetrische Pushs/Pops Szenarios böte sich da auch noch TLightweightMREW an.

Push und Pop sind aber immer schreibende Zugriffe. Insofern sehe ich jetzt noch nicht den Vorteil eines MREW.

Rollo62 3. Jan 2022 19:33

AW: Ringpuffer Bibliothek veröffentlicht
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1500009)
Zitat:

Zitat von Rollo62 (Beitrag 1500006)
Für asymmetrische Pushs/Pops Szenarios böte sich da auch noch TLightweightMREW an.

Push und Pop sind aber immer schreibende Zugriffe. Insofern sehe ich jetzt noch nicht den Vorteil eines MREW.

Stimmt auch wieder, ist ja ein Ring und der muss immer irgendwie geschrieben werden.
Allerdings könnten einige Abfrage-Funktionen womöglich mit InterlockedFunktionen abgesichert werden,
statt mit dem großen TMonitor Aufwand.

Meine aktuelle RingBuffer-Implementierung ist auf der Basis eines TMemoryStreams gemacht
weil es dabei um Byte-Ströme geht, mit CriticalSections, damit bin ich eigentlich ganz zufrieden.
Da nutze ich InterLocked Variablen als Indexzeiger, um unnötige Locks zu Vermeiden.
Ich wollte immer mal checken ob es schnellere, bessere Alternativen gibt.
Der RingBuffer mit ThreadWrapper könnte sowas sein, werde ich mal für mich austesten.

Dein Vorschlag mit dem universellen TThreadWrapper<T: class> = class macht schon viel Sinn,
weil man es dann auch auf viele andere Probleme übertragen kann.

Ich dachte bei dem RingBuffer ursprünglich dass es eine sehr Basic-Library oder Collection ist,
welche ihre eigentliche Aufgabe aus meiner Sicht möglichst komplett eigenständig abdecken sollte.
Das bezog sich aber sehr auf meinen speziellen Anwendungsfall, wo ich Pop/Push möglichst ohne Zusatzaufwand sicher entkoppeln möchte.

Durch den Wrapper wäre die Funktionalität und ThreadSicherheit aber auch schön sauber getrennt, und das passt dann noch in zig andere Situationen rein.
Und ja, Push/Pop/Peek, etc. sorgen dafür dass es doch nicht so einfach intrinsisch threadsicher werden kann,
ich benutze es momentan so, dass wenn was Neues drin ist, dann Lese und Bearbeite es.
Ein Peek nutze ich momentan nicht.
Das Duo mit dem Wrapper gefällt mir immer besser, wenn ich mal tiefer drüber nachdenke.

TurboMagic 3. Jan 2022 19:47

AW: Ringpuffer Bibliothek veröffentlicht
 
Dann speise es nach deinen Tests bitte bei dem Projekt ein...
...damit auch die Allgemeinheit davon profitiert.

Grüße
TurboMagic

Stevie 4. Jan 2022 09:41

AW: Ringpuffer Bibliothek veröffentlicht
 
Im Idealfall sollte ein thread-safer Ringbuffer lock-free sein und nicht einfach stumpf ne CS oder sowas nutzen.

TurboMagic 4. Jan 2022 09:45

AW: Ringpuffer Bibliothek veröffentlicht
 
Zitat:

Zitat von Stevie (Beitrag 1500039)
Im Idealfall sollte ein thread-safer Ringbuffer lock-free sein und nicht einfach stumpf ne CS oder sowas nutzen.

Ich verstehe nur noch nicht ganz, wie man das umsetzen könnte?
Man muss ja meistens lesen bzw. schreiben und Start bzw. Ende Index aktualisieren.
Da das zwei verschiedene Operationen sind, könnte da ja immer jemand "dazwischen" grätschen...

Uwe Raabe 4. Jan 2022 11:17

AW: Ringpuffer Bibliothek veröffentlicht
 
Zitat:

Zitat von TurboMagic (Beitrag 1500040)
Ich verstehe nur noch nicht ganz, wie man das umsetzen könnte?

Das ist ja eben das Problem bei lock-free Ansätzen... :)

Sinspin 4. Jan 2022 11:26

AW: Ringpuffer Bibliothek veröffentlicht
 
Zitat:

Zitat von Stevie (Beitrag 1500039)
Im Idealfall sollte ein thread-safer Ringbuffer lock-free sein und nicht einfach stumpf ne CS oder sowas nutzen.

Ich denke ab mehr als einem Thread, der Daten schreibt oder liest wird es sich nicht vermeiden lassen mit CS zu arbeiten. Zumindest bei jedem schreibenden Zugriff auf die Positionszeiger.
Aber selbst dann können sich Fehler ergeben wenn ein Positionszeiger von mehr als einem Thread zur gleichen Zeit gelesen wird, dann würden all diese Threads auf die gleichen Datenzelle lesend oder schreibend zugreifen.
Ich kann mir nicht vorstellen wie man das ohne CS lösen kann.

Rollo62 4. Jan 2022 11:36

AW: Ringpuffer Bibliothek veröffentlicht
 
Zitat:

Zitat von TurboMagic (Beitrag 1500040)
Zitat:

Zitat von Stevie (Beitrag 1500039)
Im Idealfall sollte ein thread-safer Ringbuffer lock-free sein und nicht einfach stumpf ne CS oder sowas nutzen.

Ich verstehe nur noch nicht ganz, wie man das umsetzen könnte?

Das könnte vielleicht mit viel Interlocked Pointer-Einsatz gehen, würde ich mal vermuten.
https://ferrous-systems.com/blog/lock-free-ring-buffer/

Aber das wäre dann sicher schon die nächste Ausbaustufe des RingBuffers.

TurboMagic 4. Jan 2022 12:12

AW: Ringpuffer Bibliothek veröffentlicht
 
Wie gesagt: der Autor der Bibliothek ist offen für Code Beiträge ;-)

Stevie 4. Jan 2022 13:20

AW: Ringpuffer Bibliothek veröffentlicht
 
AFAIK hat die OTL sowas schon

TurboMagic 7. Jan 2022 17:05

AW: Ringpuffer Bibliothek veröffentlicht
 
Zitat:

Zitat von Rollo62 (Beitrag 1500055)
Zitat:

Zitat von TurboMagic (Beitrag 1500040)
Zitat:

Zitat von Stevie (Beitrag 1500039)
Im Idealfall sollte ein thread-safer Ringbuffer lock-free sein und nicht einfach stumpf ne CS oder sowas nutzen.

Ich verstehe nur noch nicht ganz, wie man das umsetzen könnte?

Das könnte vielleicht mit viel Interlocked Pointer-Einsatz gehen, würde ich mal vermuten.
https://ferrous-systems.com/blog/lock-free-ring-buffer/

Aber das wäre dann sicher schon die nächste Ausbaustufe des RingBuffers.

Und, welchen Ansatz benutzt du nun?

Grüße
TurboMagic

Rollo62 8. Jan 2022 11:10

AW: Ringpuffer Bibliothek veröffentlicht
 
Zitat:

Zitat von TurboMagic (Beitrag 1500234)
Und, welchen Ansatz benutzt du nun?

Wie schon gesagt, basierend auf TMemoryStream, mit Interlocked Pointern und Flags zur möglichst effizienten Kontrolle der aktuellen Start/End Pointer, und zur Minimierung von echten CriticalSections.
Ich brauche das im Moment um zufällig eingehende TBytes Sendungen mit variabler Länge, von regelmäßigen Bearbeitungen , welche diese TBytes Daten abholen und verarbeiten sicher zu entkoppeln.
Also es kann gerade etwas abgeholt werden, wenn zufällig neue Daten reinkommen, das muss abgesichert werden.
Das basiert allerdings auf linearen Speicher und ist auf Byte-Stream-Weise Ein- und Ausgabe optimiert,
also ist es mit dem universellen Ringbuffer in dem man Alles reinwerfen kann nicht ganz kompatibel.
( Oder zumindest wäre ein direkter Vergleich etwas unfair ).

Ich könnte auch einen FIFO-artigen, linearen Speicher dafür nehmen, müsste dann aber verhindern dass der unendlich anwächst, deshalb hatte ich RingBuffer eingesetzt.
In meinem Fall wäre das aber sicher auch mit einem längenbegrentzen FIFO möglich,
vom RingBuffer erhoffe ich mir allerdings unnötiges Umkopieren/Löschen von Bytes zu verhindern.
Ein Ringbuffer muss ja nicht entsorgt werden, sondern der StartPointer (Integer) läuft einfach bis zum EntPointer (Integer), und die alten Daten bleiben einfach unangetastet im Ring, das kostet fast gar nichts.

Trotzdem checke ich immer mal wieder wie sich Alternativen dazu verhalten und ob es gute Ideen dazu gibt.

Uwe Raabe 8. Jan 2022 11:44

AW: Ringpuffer Bibliothek veröffentlicht
 
Zitat:

Zitat von Rollo62 (Beitrag 1500259)
und die alten Daten bleiben einfach unangetastet im Ring

Das geht auch nur solange gut, bis der generische Ringbuffer mit Managed Types verwendet wird. Dann muss beim Entfernen eventuell schon was mit den alten Daten passieren (z.B. Interfaces auf nil setzen). Das bedeutet manchmal eben auch Schreibzugriffe auf den Bufferspeicher zusätzlich zu den Pointern mit allem was es bei Multithreading dabei zu beachten gibt. Generics sind halt nicht trivial und verursachen oft einen ziemlichen Overhead, der bei simplen Typen zwar redundant ist, aber nicht immer so leicht wegoptimiert werden kann.

Rollo62 8. Jan 2022 13:19

AW: Ringpuffer Bibliothek veröffentlicht
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1500264)
Zitat:

Zitat von Rollo62 (Beitrag 1500259)
und die alten Daten bleiben einfach unangetastet im Ring

Das geht auch nur solange gut, bis der generische Ringbuffer mit Managed Types verwendet wird.

Genau, ich rede ja auch nur von meiner Anwendung, mit reinen TBytes Streams.
Dass der universelle RingBuffer so nicht optimiert werden kann ist klar.
Deshalb schreibe ich ja dass ein Vergleich mit Äpfeln und Birnen etwas unfair ist :stupid:

mytbo 22. Jan 2022 20:18

AW: Ringpuffer Bibliothek veröffentlicht
 
Zitat:

Zitat von TurboMagic (Beitrag 1500234)
Und, welchen Ansatz benutzt du nun?

Vielleicht liefert dir dieser Blog Artikel und die weiterführenden Links zusätzliche Inspiration: Three Locks To Rule Them All.

Bis bald...
Thomas

TurboMagic 23. Jan 2022 09:48

AW: Ringpuffer Bibliothek veröffentlicht
 
Zitat:

Zitat von mytbo (Beitrag 1501051)
Zitat:

Zitat von TurboMagic (Beitrag 1500234)
Und, welchen Ansatz benutzt du nun?

Vielleicht liefert dir dieser Blog Artikel und die weiterführenden Links zusätzliche Inspiration: Three Locks To Rule Them All.

Bis bald...
Thomas

Danke für den Link. Du darfst so einenen Lock Mechanismus gerne inform einer Kindklasse beitragen. Ich freue mich über von anderen beigesteuerte Code Erweiterungen, gerne auch ersmal in einem eigenen branch auf GitHub.

Grüße
TurboMagic


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:00 Uhr.

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 by Thomas Breitkreuz