![]() |
Thread sicheren Datenpuffer
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. |
AW: Thread sicheren Datenpuffer
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:
Ansonsten solltest du die Klasse entsprechend erweitern
FIFO.Lock;
try i := FIFO.BufferReadSize; P := GetMem(i); FIFO.Read(P, i); finally FIFO.Unlock; end;
Delphi-Quellcode:
So daß man nur die maximale Größe des Speichers angibt und dann über das Result erfährt, wieviel wirklich gelesen/geschrieben wurde.
function TFIFOStream.Peak(Buffer: Pointer; BufferSize: Integer): Integer;
function TFIFOStream.Read(Buffer: Pointer; BufferSize: Integer): Integer; function TFIFOStream.Write(Buffer: Pointer; BufferSize: Integer): Integer; 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. |
AW: Thread sicheren Datenpuffer
Oi, warum ist eig. das manuelle Kopieren schneller als die direkt dafür bereitgestellten Befehle (lodsb/stosb) zu benützen?
Zitat:
Delphi-Quellcode:
Ich könnts mir das höchstens dann vorstellen, wenn die CPU Cycle Zahl höher ist als die des ursprünglichen Codes...
@Loop:
lodsb stosb loop @Loop 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! :gruebel: |
AW: Thread sicheren Datenpuffer
Ich dachte auch mal LOOP wäre ein schöner Befehl, aber er ist leider extrem langsam.
|
AW: Thread sicheren Datenpuffer
Vielen Dank! Werde ich so mit Lock/Unlock umsetzen!
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:42 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-2025 by Thomas Breitkreuz