AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Thread sicheren Datenpuffer

Ein Thema von schwa226 · begonnen am 7. Jul 2011 · letzter Beitrag vom 8. Jul 2011
Antwort Antwort
schwa226

Registriert seit: 4. Apr 2008
400 Beiträge
 
#1

Thread sicheren Datenpuffer

  Alt 7. Jul 2011, 18:33
Hallo!

Ich habe hier einen FIFO Puffer entdeckt. Nun ist meine Frage, ob dieser auch Threadsicher ist!?
Also ein Thread schiebt daten rein. Der andere der den Buffer auch erstellt holt sich dann die Daten wieder raus.

Oder muss man hier noch Critical Sections beim Read/Write einfügen?

Delphi-Quellcode:
//(C) Peter Morris - pete@stuckindoors.com / pete@droopyeyes.com
unit uFIFOStream;

interface

uses
  Windows, Messages, SysUtils, Classes;

type
  EFIFOStream = class(Exception);

  TFIFOStream = class(TObject)
    private
      FData : PByte;
      FMemorySize : Integer;
      FBufferEnd,
      FBufferStart : Integer;
    protected
    public
      constructor Create(aSize : Integer); virtual;
      destructor Destroy; override;
      function BufferReadSize : Integer;
      function BufferWriteSize : Integer;
      procedure Clear;
      procedure Peek(const aBuffer : Pointer; Count : Integer);
      procedure Read(const aBuffer : Pointer; Count : Integer);
      procedure Write(const aSource : Pointer; Count : Integer);
    published
  end;

implementation

procedure ByteMove(const Source; var Dest; Count : Integer);
asm

  //Note: When this function is called, delphi passes the parameters as follows
  //ECX = Count
  //EAX = Const Source
  //EDX = Var Dest

    //If no bytes to copy, just quit altogether, no point pushing registers
    cmp ECX,0
    Je @JustQuit

    //Preserve the critical delphi registers
    push ESI
    push EDI

    //move Source into ESI (generally the SOURCE register)
    //move Dest into EDI (generally the DEST register for string commands)
    //This may not actually be neccessary, as I am not using MOVsb etc
    //I may be able just to use EAX and EDX, there may be a penalty for
    //not using ESI, EDI but I doubt it, this is another thing worth trying !
    mov ESI, EAX
    mov EDI, EDX

  //The following loop is the same as repNZ MovSB, but oddly quicker !
  @Loop:
    //Get the source byte
    Mov AL, [ESI]
    //Point to next byte
    Inc ESI
    //Put it into the Dest
    mov [EDI], AL
    //Point dest to next position
    Inc EDI
    //Dec ECX to note how many we have left to copy
    Dec ECX
    //If ECX <> 0 then loop
    Jnz @Loop

    pop EDI
    pop ESI
  @JustQuit:
end;

{ TFIFOStream }

function TFIFOStream.BufferReadSize: Integer;
begin
if FBufferEnd >= FBufferStart then //Not looped
  Result := FBufferEnd - FBufferStart
else //Looped
  Result := FMemorySize - FBufferStart + FBufferEnd;
end;

function TFIFOStream.BufferWriteSize: Integer;
begin
  Result := FMemorySize - BufferReadSize;
end;

procedure TFIFOStream.Clear;
begin
  FBufferEnd := 0;
  FBufferStart := 0;
end;

constructor TFIFOStream.Create(aSize: Integer);
begin
  inherited Create;
  // if aSize < 1024 then
  // raise EFIFOStream.Create('Buffer size must be at least 1K.');
  FMemorySize := aSize;
  Getmem(FData, FMemorySize);
  FBufferStart := 0;
  FBufferEnd := 0;
end;

destructor TFIFOStream.Destroy;
begin
  FreeMem(FData);
  inherited;
end;

procedure TFIFOStream.Peek(const aBuffer: Pointer; Count: Integer);
var
  OrigStart : Integer;
begin
  OrigStart := FBufferStart;

  try
    Read(aBuffer, Count);
  finally
    FBufferStart := OrigStart;
  end;
end;

procedure TFIFOStream.Read(const aBuffer : Pointer; Count: Integer);
var
  Source,
  Dest : PByte;
  CopyLen : Integer;
begin
  Source := @FData[FBufferStart];
  Dest := aBuffer;

  if BufferReadSize < Count then
    raise EFIFOStream.Create('Buffer under-run.');

  CopyLen := FMemorySize - FBufferStart;
  if CopyLen > Count then
    CopyLen := Count;
  ByteMove(Source^,Dest^,CopyLen);

  Inc(FBufferStart,CopyLen);

  //If looped
  if FBufferStart >= FMemorySize then
  begin
    FBufferStart := FBufferStart - FMemorySize;
    Read(@Dest[CopyLen],Count-CopyLen);
  end;
end;

procedure TFIFOStream.Write(const aSource : Pointer; Count: Integer);
var
  Source,
  Dest : PByte;
  CopyLen : Integer;
begin
  Source := aSource;
  Dest := @FData[FBufferEnd];

  if BufferWriteSize < Count then
    raise EFIFOStream.Create('Buffer over-run.');

  CopyLen := FMemorySize - FBufferEnd;
  if CopyLen > Count then CopyLen := Count;
  ByteMove(Source^,Dest^,CopyLen);
  Inc(FBufferEnd,CopyLen);

  //If looped
  if FBufferEnd >= FMemorySize then
  begin
    FBufferEnd := FBufferEnd - FMemorySize;
    Write(@Source[CopyLen],Count-CopyLen);
  end;
end;

end.
Delphi 2010, Update 4 & 5
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#2

AW: Thread sicheren Datenpuffer

  Alt 7. Jul 2011, 19:04
Nö, ist natürlich nicht threadsicher.

> Das mußt du alles absichern
BufferReadSize
BufferWriteSize
Clear
Peek
Read
Write

> Das sollte man besser auch mit absichern:
Destroy

> Nur dieses brauchst'e nicht, da dort sowieso noch kein anderer Thread drauf zugreifen kann:
Create


Falls du von extern z.B. auch noch zusammenhängend auf BufferReadSize und Peek/Read zugreifen willst, bräuchtest du noch sowas wie ein Lock und Unlock nach außen, damit man die zusammenhängenden Befehle auch zusammen absichern kann.

Delphi-Quellcode:
FIFO.Lock;
try
  i := FIFO.BufferReadSize;
  P := GetMem(i);
  FIFO.Read(P, i);
finally
  FIFO.Unlock;
end;
Ansonsten solltest du die Klasse entsprechend erweitern
Delphi-Quellcode:
function TFIFOStream.Peak(Buffer: Pointer; BufferSize: Integer): Integer;
function TFIFOStream.Read(Buffer: Pointer; BufferSize: Integer): Integer;
function TFIFOStream.Write(Buffer: Pointer; BufferSize: Integer): Integer;
So daß man nur die maximale Größe des Speichers angibt und dann über das Result erfährt, wieviel wirklich gelesen/geschrieben wurde.

Wobei man stattdessen auch einen Boolean(False) zurückgeben oder eine Exception werfen könnte, wenn der Speicher (Count) nicht vollständig speicherbar/lesbar wäre und dabei im FIFO nix ändert.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu ( 7. Jul 2011 um 19:09 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Aphton
Aphton

Registriert seit: 31. Mai 2009
1.198 Beiträge
 
Turbo Delphi für Win32
 
#3

AW: Thread sicheren Datenpuffer

  Alt 7. Jul 2011, 20:14
Oi, warum ist eig. das manuelle Kopieren schneller als die direkt dafür bereitgestellten Befehle (lodsb/stosb) zu benützen?
Zitat:
"The following loop is the same as repNZ MovSB, but oddly quicker")
Also wäre das hier langsamer als der Quellcode oben?
Delphi-Quellcode:
  @Loop:
    lodsb
    stosb
    loop @Loop
Ich könnts mir das höchstens dann vorstellen, wenn die CPU Cycle Zahl höher ist als die des ursprünglichen Codes...
Aber das glaube ich kaum!

Edit:
Wenn ich richtig schätze - lodsb & stosb machen ein mov & inc
und loop ein dec und conditional-jump (worst case; sonst Optimierung?)
Im Grunde ist also die Anzahl der Befehle gleich und es handelt sich sogar um dieselben Befehle!
das Erkennen beginnt, wenn der Erkennende vom zu Erkennenden Abstand nimmt
MfG

Geändert von Aphton ( 7. Jul 2011 um 20:23 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#4

AW: Thread sicheren Datenpuffer

  Alt 7. Jul 2011, 21:23
Ich dachte auch mal LOOP wäre ein schöner Befehl, aber er ist leider extrem langsam.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
schwa226

Registriert seit: 4. Apr 2008
400 Beiträge
 
#5

AW: Thread sicheren Datenpuffer

  Alt 8. Jul 2011, 08:17
Vielen Dank! Werde ich so mit Lock/Unlock umsetzen!
Delphi 2010, Update 4 & 5
  Mit Zitat antworten Zitat
Antwort Antwort


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 02:16 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