Einzelnen Beitrag anzeigen

alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#17

Re: Array in Thread übergeben

  Alt 8. Jun 2005, 14:57
@messie: Das mit dem 'schlafen' legen war nicht so gemeint (Suspend/Resume), sondern im übertragenen Sinne per WaitForSingleObject. Suspend/Resume benutzte ich nur beim Create (Suspended)...Initialisierung...Resume.
Ansonsten benutze ich WaitForSingleObject.

@Ossi: Ich meine, das die beiden Threads voll parallel laufen werden. T1 schreibt in B1 während T2 von B2 liest und umgekehrt.
Hier ist mal so ein Buffer. Put Put schiebst du was rein (von Thread #1) und kannst gleichzeitig von Thread #2 pber 'Get' was rauslesen.

'Get' wartet, bis was im Puffer ist.
'Put' wartet, bis der Puffer nicht mehr voll ist.

Ich verwende 2 Events, eins, um zu signalisieren, das der Buffer voll ist, und eins für 'ist leer'.
Die Modifikation des Ringbuffers ist durch eine CriticalSection geschützt.

Ich würde mit einer Puffergröße von >=3 arbeiten. Als 'Items' nimmst Du Deine 1000er Blöcke.

Viel Spass

Delphi-Quellcode:
unit csBuffer;

interface
uses SysUtils, Classes, windows, SyncObjs;
Type
(* Implementierung eines einfachen Ringbuffers mit einem Event.
* "Put" wartet, bis der Buffer nicht mehr voll ist und schreibt dann ein
* Element in den Buffer.
* "Get" wartet, bis etwas im Buffer ist und liefert das älteste Element
*)

  TRingBuffer = Class (TObject)
  Private
    FItems : Array Of Pointer;
    FTotal, FSize,
    FHead, FTail : Integer;
    FCS : TCriticalSection;
    FIsFullEvent, FIsEmptyEvent : TEvent;
  Public
    Constructor Create (aTotalSize : Integer);
    Destructor Destroy;
    Procedure Put (aItem : Pointer);
    Procedure Get (Var aItem : Pointer);
    End;

implementation

{ TRingBuffer }

constructor TRingBuffer.Create(aTotalSize: Integer);
begin
  Inherited Create;
  FSize := aTotalSize;
  SetLength (fItems, aTotalSize);
  FHead := 0;
  FTotal := 0;
  FTail := 0;
  fCS := TCriticalSection.Create;
  FIsFullEvent := TEvent.Create(nil,True,True,'');
  FIsEmptyEvent := TEvent.Create(nil,True,False,'');
end;

destructor TRingBuffer.Destroy;
begin
  SetLength (fItems,0);
  fCS.Free;
  FIsEmptyEvent.Free;
  FIsFullEvent.Free;
  Inherited;
end;

procedure TRingBuffer.Put(aItem: Pointer);
Var
  lIsEmpty : Boolean;
  NewHead : Integer;
begin
// Warten, bis der Buffer nicht mehr voll ist
  if FIsFullEvent.WaitFor (INFINITE) = wrSignaled Then Begin
    fCS.Enter;
    Try
      FItems [FHead] := aItem; // Element vorne anhängen
      FHead := (FHead + 1) mod FSize; // Vorne um eins nach vorne ;-)
      If FTotal = 0 Then // Wenn der Buffer leer war, dann
        FIsEmptyEvent.SetEvent; // isser jetzt nicht mehr leer
      Inc (FTotal);
    Finally
      fCS.Leave;
      End
    End
  Else Raise Exception.Create ('Systemfehler');
end;

procedure TRingBuffer.Get(var aItem: Pointer);
begin
// Warten, bis der Buffer nicht leer ist
  if FIsEmptyEvent.WaitFor(INFINITE) = wrSignaled Then Begin
    fCS.Enter;
    Try
      aItem := FItems [FTail]; // Letztes Element abholen
      FTail := (FTail + 1) mod FSize;
      if FTotal = 1 Then // Wenn es leer wird, dann Event zurücksetzen
        FIsEmptyEvent.ResetEvent
      Else If FTotal = FSize Then // Wenn es voll war, dann Event setzen
        FIsFullEvent.SetEvent;
      Dec (FTotal);
    Finally
      fCS.Leave;
      End
    End
  Else Raise Exception.Create ('Systemfehler');
end;

end.
Und so arbeiten die threads:
Delphi-Quellcode:
While not Terminated do Begin
  fBuffer.Get (aData);
  SaveToFile (aData);
  End;
und der Andere:
Delphi-Quellcode:
While not Terminated do Begin
  GetCANData (aData)
  fBuffer.Put (aData);
  End;
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat