AGB  ·  Datenschutz  ·  Impressum  







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

Arbeiten mit TThreadlist

Ein Thema von norwegen60 · begonnen am 19. Jan 2017 · letzter Beitrag vom 20. Jan 2017
Antwort Antwort
norwegen60

Registriert seit: 23. Dez 2007
Ort: Schwarzwald
529 Beiträge
 
Delphi 12 Athens
 
#1

AW: Arbeiten mit TThreadlist

  Alt 20. Jan 2017, 01:08
Hallo Zacherl,

vielen Dank für die gute Erklärung. Auf die Idee, die Daten zu kopieren bin ich auch gekommen und habe es so umgesetzt.
Delphi-Quellcode:
type
  TValues = Class
    dtTime : TDateTime;
    rForce,
    rTemperature,
    rHumidity : Real;
  End;

....

procedure TListThread.Execute;
var
  s:String;
  I, i1: Integer;
  Values: TValues;
  tmpList,
  my1List: TList;
  dtOld : TDateTime;
  rTdelta :REal;
begin
  while(True) do
  begin
    if (Terminated) then
    begin
      listthreadRunning:= FALSE;
      exit;
    end;

    my1List := TList.Create;
    // Noch nicht bearbeitete Daten in Temporäre Liste kopieren
    try
      tmpList := threadList1.LockList;
      for I := i1 to tmpList.Count-1 do
      begin
        Values:= TValues.Create;
        Values:= tmpList.Items[I];
        my1List.Add(Value);
      end;
      i1 := i;
    finally
      threadList1.UnlockList;
    end;

    // Kopierte Daten abhandeln (z.B. in DB speichern) und Liste wieder löschen
    try
      for I := 0 to my1List.Count-1 do
      begin
        Values:= my1List.Items[I];
        rTdelta := (Values.dtTime - dtOld)*(24*60*60);
        s:=formatDateTime('yyyy-mm-dd HH:MM:SS.zzz',Values.dtTime)+ format(': %.7d, %5.3f s', [i1, rTdelta]);
        Form1.ListBox1.Items.Add(s);
        dtOld := Temp.dtTime;
// Values.Free; // Speicher wieder freigeben NOTWENDIG ?? Führt zu Fehler
      end;
      Form1.Listbox1.ItemIndex := Form1.Listbox1.Count-1; // Auf letzte Zeile in Listbox springen
    finally
      while my1List.Count > 0 do
        my1List.Delete(0); // NOTWENDIG ??
      my1List.Free;
    end;

    Sleep(100);
  end;
  listthreadRunning:= FALSE;
end;
Da ich bisher nie mit Listen gearbeitet habe wäre ich froh wenn jemannd drauf schaut um mir zu sagen wo ich Problemstellen kreiert habe. Ich bin z.B. nicht sicher, was ich wieder freigeben muss. Viele Beispiele machen einfach my1List.Free .
Wenn ich allerdings Value.Free; aufrufe stimmt meine Liste nicht mehr

Vielen Dank
Gerd

Geändert von norwegen60 (20. Jan 2017 um 01:14 Uhr)
  Mit Zitat antworten Zitat
HolgerX

Registriert seit: 10. Apr 2006
Ort: Leverkusen
989 Beiträge
 
Delphi 6 Professional
 
#2

AW: Arbeiten mit TThreadlist

  Alt 20. Jan 2017, 04:52
Hmm..

Wieso umkopieren?
Während des Umkopieren ist die Liste gelockt, ein Hinzufügen würde nicht möglich sein...


Alternative:

Delphi-Quellcode:
procedure TListThread.Add(AItem : TValues);
begin
  tmpList := threadList1.LockList; // Liste Locken
  try
    tmpList.Add(AItem); // Item anhängen
  finally
    threadList1.UnlockList; // Liste Unlock
  end;
end;



procedure TListThread.Execute;
var
  Temp: TValues ;
  tmpList : TList;
begin
  ListthreadRunning:= true;

  while(not Terminated) do // Dauerschleife
  begin
    Temp := nil;

    tmpList := threadList1.LockList; // Liste Locken
    try
      if tmpList.Count > 0 then // Sind EIntrage vorhanden
      begin
        Temp:= tmpList.Items[0]; // Nur den ersten nehmen
        tmpList.Delete(0); // den Ersten aus der Liste entfernen
      end;
    finally
      threadList1.UnlockList; // Liste Unlock
    end;

    if Assigned(Temp) then
      DoItemWork(Temp); // -> Verarbeiten (Datenbank), während Liste wieder frei zum Füllen

    Sleep(1); // anderem Thread Zeit geben

  end; // While..
  listthreadRunning:= false;
end;
Da Du ja eh in einer (While) Dauerschleife bist, kannst du ja nach dem FIFO-Prinzip immer nur den ersten Eintrag aus der Liste nehmen, wenn er vorhanden ist.

Nur während des Überprüfen, ob eine Eintrag vorhanden ist und der Entnahme ist die Liste gelockt (sehr kurz).

Die Verarbeitung des Eintrages erfolgt außerhalb des Locks und somit kann währenddessen weiter neue Einträge angehängt werden.

Neue Einträge können also ohne große Verzögerung angehängt werden, ungestört von der Datenbank-Aktion.
  Mit Zitat antworten Zitat
norwegen60

Registriert seit: 23. Dez 2007
Ort: Schwarzwald
529 Beiträge
 
Delphi 12 Athens
 
#3

AW: Arbeiten mit TThreadlist

  Alt 20. Jan 2017, 07:49
Hallo,

cih werde mir auch das mal genauer anschauen. Ich möchte allerdings die Ursprungsliste nicht löschen, da ich die Daten auch anzeigen oder ausgeben möchte. Und dann geht es mir auch ums Verständnis ob mein Ansatz korrekt ist.

Gerd
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#4

AW: Arbeiten mit TThreadlist

  Alt 20. Jan 2017, 08:51
Wieso umkopieren?
Während des Umkopieren ist die Liste gelockt, ein Hinzufügen würde nicht möglich sein...
Dein Ansatz wird vermutlich tatsächlich noch performanter sein. Dann würde ich aber direkt eine TQueue<> nehmen und den Zugriff manuell mit einem TMonitor btw. einer TCriticalSection absichern. Tatsächlich bevorzuge ich nach wie vor den RingBuffer Ansatz, da dort die Memory Operationen eingespart werden können und man mit lediglich zwei Pointern/Indizes sehr einfach das FIFI Prinzip umsetzen kann. TMonitor implementiert sogar schon eine Form des Spin-Lockings, washalb man nichtmal manuell mit TInterlocked arbeiten müsste.

Statt Sleep(1) geht btw. auch TThread.Yield() . Das ist etwas intuitiver zu verstehen, falls mal jemand anderes den Code lesen sollte.

Edit:
Meine Überlegung bezüglich des Kopierens und Verarbeiten der Liste in einem Thread war im Grunde genommen die folgende Datenbank-Operation. Hier kann ich mir gut vorstellen, dass viele Inserts mit einer einzelnen Value deutlich langsamer sind, als das einmalige Inserten mehrerer Werte.

ich möchte allerdings die Ursprungsliste nicht löschen, da ich die Daten auch anzeigen oder ausgeben möchte. Und dann geht es mir auch ums Verständnis ob mein Ansatz korrekt ist.
Puh, also da wird dir bei einer 45 Minütigen Datensammlung aber ziemlich der Speicher volllaufen. Ich würde das Anzeigen der Daten direkt im Producer Thread erledigen, oder notfalls noch einen dritten Thread erstellen, der das übernimmt.

Dein Code sieht noch nicht korrekt aus. Ich schaue im Laufe des Tages nochmal genauer drüber, sobald ich Zeit habe.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)

Geändert von Zacherl (20. Jan 2017 um 09:47 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#5

AW: Arbeiten mit TThreadlist

  Alt 20. Jan 2017, 14:21
Hier mal noch die Alternative mit einer Queue (erscheint mir mit Boardmitteln und ohne großen Aufwand die eleganteste Lösung zu sein):
Delphi-Quellcode:
type
  TDataStruct = record
  public
    Timestamp: Cardinal;
    Value: Integer;
  end;
var
  Queue: TQueue<TDataStruct>;
begin

  Queue := TQueue<TDataStruct>.Create;
  try
    // Producer
    TThread.CreateAnonymousThread(
      procedure
      var
        Item: TDataStruct;
        Counter: Integer;
      begin
        Counter := 0;
        while True do
        begin
          // Collect data
          Item.Timestamp := GetTickCount;
          Item.Value := Counter;
          Inc(Counter);
          // Enqueue
          System.TMonitor.Enter(Queue);
          try
            Queue.Enqueue(Item);
          finally
            System.TMonitor.Exit(Queue);
          end;
          Yield;
        end;
      end).Start;

    // Consumer
    TThread.CreateAnonymousThread(
      procedure
      var
        Item: TDataStruct;
      begin
        while True do
        begin
          // Dequeue
          System.TMonitor.Enter(Queue);
          try
            if (Queue.Count > 0) then
            begin
              Item := Queue.Dequeue;
            end;
          finally
            System.TMonitor.Exit(Queue);
          end;
          // Work with local copy
          // ...
          WriteLn(Item.Value);
        end;
      end).Start;

  finally
    Queue.Free;
  end;
end;
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
norwegen60

Registriert seit: 23. Dez 2007
Ort: Schwarzwald
529 Beiträge
 
Delphi 12 Athens
 
#6

AW: Arbeiten mit TThreadlist

  Alt 20. Jan 2017, 16:37
Oje, mir raucht der Kopf. Aber ich werde auch das anschauen.

Ich wüsste aber auch gerne, was in meinem Ansatz korrigiert werden müsste. Von der Performance konte ich nichts nachteiliges feststellen. Selbst bei 1ms Intervallen gab es keine Verzögerungen bei der Erfassung der Daten. Nur bei der Freigabe der Speicher bin ich nicht sicher.
  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:05 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