Einzelnen Beitrag anzeigen

schwa226

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

Thread sicheren Datenpuffer

  Alt 7. Jul 2011, 17: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