AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Sonstige Fragen zu Delphi Delphi Liste (ähnlich dyn Array) mit fortlaufendem Index?
Thema durchsuchen
Ansicht
Themen-Optionen

Liste (ähnlich dyn Array) mit fortlaufendem Index?

Ein Thema von moelski · begonnen am 24. Mär 2010 · letzter Beitrag vom 29. Mär 2010
Antwort Antwort
Seite 3 von 4     123 4      
moelski

Registriert seit: 31. Jul 2004
1.110 Beiträge
 
Delphi 2010 Professional
 
#21

Re: Liste (ähnlich dyn Array) mit fortlaufendem Index?

  Alt 25. Mär 2010, 13:14
So nochmal ich.

Der Code lässt sich nun schon mal übersetzen. Danke Dirk.
Funktioniert nur noch nicht so wie gedacht ...

Beim ersten Eintrag geht alles glatt. Das Event wird gesetzt, der Thread rennt an, er verarbeitet die Daten und macht das Dispose.

Wenn ich einen zweiten Eintrag hinzufüge macht der Thread aber nüscht mehr auch wenn das event abgefeuert wird.
Laufe tut der Thread allerdings wohl noch - sieht man ja im Debugger.

Zum Erzeugen der Klasse und des Thread nutze ich den Code:
Delphi-Quellcode:
var Form3 : TForm3;
    Kette : TDataClass;
    Work : TWorker;

implementation

procedure TForm3.Button1Click(Sender: TObject);
begin
  Kette.Add('Name', 1, 2, 3, 4);
end;

procedure TForm3.FormCreate(Sender: TObject);
begin
  Kette := TDataClass.Create;
  work := TWorker.Create(Kette);
  work.Start;
end;
Dominik Schmidt
Greetz Dominik

I love Delphi 2007/2010
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

Re: Liste (ähnlich dyn Array) mit fortlaufendem Index?

  Alt 25. Mär 2010, 13:23
OK, dann ist der fortlaufende Index für den Zugriff garnichtmal nötig.

Hier gibt es aber erstmal ein Problem:
Wenn jetzt zwei Threads immer alle Daten verarbeiten sollen und gleichzeigtig einer der Threads die Liste löschen würde.

Lösungen:
- entweder für jeden der Threads eine eigene Liste
- oder Beides in einem Thread lösen (also die beiden Dateien zusammen erstellen)

Die Abfrage der aktuellen Werte, für das Livemonitorin würde ich dann auch nicht über diese Liste machen, denn was willst du Anzeigen, wenn gerade in diesem Moment diese Liste noch/wieder leer ist?
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
moelski

Registriert seit: 31. Jul 2004
1.110 Beiträge
 
Delphi 2010 Professional
 
#23

Re: Liste (ähnlich dyn Array) mit fortlaufendem Index?

  Alt 25. Mär 2010, 13:30
Moin !

Zitat:
- oder Beides in einem Thread lösen (also die beiden Dateien zusammen erstellen)
Das wäre durchaus machbar.

Zitat:
Die Abfrage der aktuellen Werte, für das Livemonitorin würde ich dann auch nicht über diese Liste machen, denn was willst du Anzeigen, wenn gerade in diesem Moment diese Liste noch/wieder leer ist?
Ok da hast du Recht. Dafür sollte man die letzten Werte extra vorhalten. Aber erstmal musses ja funzionieren

Ich denke der Code kommt noch ein bisserl durcheinander mit FFirst und FLast. Denn kann ja nicht sein das FLast noch einen Pointer beinhaltet obwohl der einzige dateneintrag gerade verarbeitet wurde:
Miniaturansicht angehängter Grafiken
flast_196.png  
Dominik Schmidt
Greetz Dominik

I love Delphi 2007/2010
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

Re: Liste (ähnlich dyn Array) mit fortlaufendem Index?

  Alt 25. Mär 2010, 13:47
Wenn du die Live-Werte extra vorhälst, dann wird FLast nicht benötigt und eine stinknormale einfach verkettete Liste reicht vollkommen aus.

ach nee, für's Anhängen neuer Daten wird FLast ja dennoch benötigt.

Delphi-Quellcode:
uses
  Windows, Classes, SysUtils, SyncObjs;

type
  POneData = ^TOneData;
  TOneData = record
    Text: string;
    Value1: Double;
    Value2: Double;
    Value3: Double;
    Value4: Double;
    Next: POneData;
  end;

  TDataClass = class
  private
    FEvent: TEvent;
    FLock: TCriticalSection;
    FFirst, FLast: POneData;
    FLive: TOneData;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Add(const Name: string; const V1, V2, V3, V4: Double);
    function ExtractAll: POneData;
    function GetLive: TOneData;
    function WaitAndCheckForNewData(TimeOut: Cardinal): Boolean;
  end;

  TWorker = class(TThread)
  private
    FDataClass: TDataClass;
  protected
    procedure Execute; override;
  public
    constructor Create(DataClass: TDataClass);
  end;



constructor TDataClass.Create;
begin
  inherited Create;
  FEvent := TEvent.Create(nil, True, False, '');
  FLock := TCriticalSection.Create;
end;

destructor TDataClass.Destroy;
var
  tmp: POneData;
begin
  while FFirst <> nil do
  begin
    tmp := FFirst;
    FFirst := FFirst.Next;
    Dispose(tmp);
  end;
  FEvent.Free;
  FLock.Free;
  inherited Destroy;
end;

procedure TDataClass.Add(const Name: string; const V1, V2, V3, V4: Double);
var
  NewData: POneData;
begin
  New(NewData);
  NewData.Text := Name;
  NewData.Value1 := V1;
  NewData.Value2 := V2;
  NewData.Value3 := V3;
  NewData.Value4 := V4;
  NewData.Next := nil;
  try
    FLock.Acquire;
    try
      FLive := NewData^;
      if Assigned(FLast) then
      begin
        FLast.Next := NewData;
        FLast := NewData;
      end else
      begin
        FFirst := NewData;
        FLast := FFirst;
      end;
      FEvent.SetEvent;
    finally
      FLock.Release;
    end;
  except
    Dispose(NewData);
  end;
end;

function TDataClass.ExtractAll: POneData;
begin
  FLock.Acquire;
  try
    FEvent.ResetEvent;
    Result := FFirst;
    FFirst := nil;
    FLast := nil;
  finally
    FLock.Release;
  end;
end;

function TDataClass.GetLive: TOneData;
begin
  FLock.Acquire;
  try
    Result := FLive;
  finally
    FLock.Release;
  end;
end;

function TDataClass.WaitAndCheckForNewData(TimeOut: Cardinal): Boolean;
begin
  Result := FEvent.WaitFor(TimeOut) = wrSignaled;
end;

procedure TWorker.Execute;
var
  PData, PData2: POneData;
begin
  repeat
    if FDataClass.WaitAndCheckForNewData(100) then
    begin
      PData := FDataClass.ExtractAll;
      try
        while Assigned(PData) do
        begin
          PData2 := PData;
          PData := PData.Next;
          try
            Verarbeite(PData2^);
          finally
            Dispose(PData2);
          end;
        end;
      except
        // falls Exception, restlichen Speicher aufräumen und Werte verwerfen
        // aber es wäre auch möglich die Daten wieder in die Liste einzufügen
        // oder man "ignoriert" Exceptions und setzt einfach die obere Schleife fort
        while Assigned(PData) do
        begin
          PData2 := PData;
          PData := PData.Next;
          Dispose(PData2);
        end;
        Raise;
      end;
    end;
  until Terminated;
end;

constructor TWorker.Create(DataClass: TDataClass);
begin
  inherited Create(True);
  FDataClass := DataClass;
  Resume;
end;
Da hier gleich die ganze Liste aus der Datenhaltung rausgeholt wird, ist diese bereit sofort neue Daten aufzunehmen und wird weniger bei Auslesen blockiert.

Bei Verarbeite werden die Daten dann einfach in beide Dateien (Rohdaten und umgerechneten CSV-Daten geschrieben).
Die aktuellsten Live-Werte bekommt man über DataClass.GetLive geliefert.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
moelski

Registriert seit: 31. Jul 2004
1.110 Beiträge
 
Delphi 2010 Professional
 
#25

Re: Liste (ähnlich dyn Array) mit fortlaufendem Index?

  Alt 25. Mär 2010, 20:07
Moin !

@himitsu:
Vielen Dank für deine Erweiterung. Das klappt nun erstaunlich gut

Auch die Speicherbelastung bleibt wie erwartet niedrig.

Hätte dann noch ein paar wetere Fragen (und hoffentlich gehe ich euch nicht zu sehr auch den Sac* ).

1) Event an Thread
Wenn ich nun möchte das der Thread nur jede Sekunde die Daten verarbeitet, dann könnte ich doch einfach in TDataClass.Add bei FEvent.SetEvent eine Zeitliche Überprüfung einbauen.
Also sowas wie Millisecondsbetween(Now, Then) >= 1000 ... ?

2) Ich möchte ja die Daten auch in ein Chart schreiben. Und am liebsten würde ich die Daten natürlich so im Chart ablegen, dass der Hauptthread der Anwendung möglichst unbelastet bleibt.
Delphi-Quellcode:
  TWorker = class(TThread)
  private
    FDataClass : TDataClass;
    FChart : TChart;
  protected
    procedure Execute; override;
  public
    constructor Create(DataClass: TDataClass; Chart : TChart);
  end;
So funktioniert das zwar im Thread, aber eigentlich müsste es ja über ein Synchronize laufen, oder? Aber das läuft ja dann wieder im Hauptthread.

3) Wie verhält sich TDataClass wenn der Hauptthread ausgelastet ist?
Derzeit erzeuge ich die Instanz von TDataClass ja im Hauptthread der Anwendung. Wenn die aber nun gerade zu 100% ausgelastet ist, was macht dann TDataClass? Dann würde doch ein Add nicht mehr zur Anwendung kommen, oder?
Das wäre natürlich fatal weil ich dann mitunter Daten verlieren könnte.
Könnte man TDataClass ggf. selber als Thread auslegen und somit vom HAuptthread abkapseln?
Dominik Schmidt
Greetz Dominik

I love Delphi 2007/2010
  Mit Zitat antworten Zitat
Tryer

Registriert seit: 16. Aug 2003
200 Beiträge
 
#26

Re: Liste (ähnlich dyn Array) mit fortlaufendem Index?

  Alt 26. Mär 2010, 16:57
Die Kommunikation mit der Peripherie sollte in einem eigenen Thread laufen welcher dann Add() aufruft. Immer wenn eine Funktion aufgerufen wird dann findet das immer im Kontext des aufrufenden Threads statt, also in einem anderen Thread als das Execute() läuft und unabhängig davon welcher Thread das Objekt erstellt hat. Solange der Kommunikationsthread (für den ich eine erhöhte Priorität empfehlen würde) zum Zuge kommt werden auch die Daten angenommen.

Da ich nicht weis wie schnell/gleichmäßig die Daten reinkommen ist es schwer zu sagen ob es sinnvoller ist eine Sekunde zu sammeln (GetTickCount o.ä.) oder von vornherein jedes Paket mit einem Zeitstempel zu versehen. Der Kommunikations-Thread könnte den Event "Daten vorhanden" z.B. nach jeweils 100 Paketen oder 1000ms setzen und der Worker übernimmt dann den ganzen Datensatz aus diesem Zeitraum (Das wäre dann vielleicht wieder die Variante mit dem Austauschen der ganzen Liste).

Mit TChart habe ich noch nicht gearbeitet, könnte mir aber prinzipiell vorstellen inn einem eigenen Thread ein Bitmap aufzubauen welches dann in einem kurzen Synchronize ausgegeben wird. Dieses Synchonize sollte auf keinen Fall aus dem Kommunikationsthread kommen damit dieser unabhängig von der Oberfläche arbeiten kann.

Grüsse, Dirk
  Mit Zitat antworten Zitat
moelski

Registriert seit: 31. Jul 2004
1.110 Beiträge
 
Delphi 2010 Professional
 
#27

Re: Liste (ähnlich dyn Array) mit fortlaufendem Index?

  Alt 27. Mär 2010, 07:48
Moin !

Zitat:
Die Kommunikation mit der Peripherie sollte in einem eigenen Thread laufen welcher dann Add() aufruft. Immer wenn eine Funktion aufgerufen wird dann findet das immer im Kontext des aufrufenden Threads statt
Bist du dir da sicher?

Sagen wir mal es gibt einen Kommunikationsthread und die Instanz der Datenklasse liegt im MainForm und damit ja eigentlich auch im MainThread.
Wenn ich nun das Add aus dem Kommu-Thread raus aufrufe, läuft das dann wirklich im Kommu-Thread ?

Zitat:
TChart & Bitmap
Das geht so nicht. Man muss die Daten schon im TChart eintragen um die Kurve zu erzeugen. Das macht die Sache nämlich zu kompliziert aus einem Thread heraus

@himitsu:
Hast du meine PN gelesen?
Dominik Schmidt
Greetz Dominik

I love Delphi 2007/2010
  Mit Zitat antworten Zitat
Tryer

Registriert seit: 16. Aug 2003
200 Beiträge
 
#28

Re: Liste (ähnlich dyn Array) mit fortlaufendem Index?

  Alt 27. Mär 2010, 08:15
Die Instanz liegt im Speicher, nicht im Threadkontext. Und alle deine Threads haben Zugriff auf den Speicher, man muss halt nur schauen das die Zugriffe geortnet ablaufen. Das wird über Synchronisierungsobjekte wie TCriticalSection oder das in TTread implementierte Synchronize durchgeführt. Synchronize legt prinzipiell die Adresse der Prozedur welche der Mainthread aufrufen soll in einer Liste ab und schickt eine Nachricht (WM_NULL) an den Mainthread das in der Liste Arbeit wartet. Bis der Mainthread das getan hat schläft der Thread, läuft also danach erst weiter. Deswegen ist Synchronize so eine Bremse welche man wirklich nur "wenn nötig" benutzen sollte. Verriegelungen die unabhängig vom Mainthread stattfinden können/dürfen sind also besser über die SyncObjekte zu realisieren.

TChart: Dann also die ValueLists für´s TChart aufbereiten und in einem Synchronize übergeben + zeichnen. Ist doch auch aus dem Thread kein Problem.

Grüsse, Dirk
  Mit Zitat antworten Zitat
moelski

Registriert seit: 31. Jul 2004
1.110 Beiträge
 
Delphi 2010 Professional
 
#29

Re: Liste (ähnlich dyn Array) mit fortlaufendem Index?

  Alt 29. Mär 2010, 10:11
Moin !

So ich habe jetzt mal alles in ein Projekt gegossen. Erstellt ist es mit D2010, aber ich denke es sollte auch mit anderen Delphi Versionen nutzebar sein.

Man kann mit dem Button "Add Input" an die verkettete Liste Daten anhängen. Das geht recht flott und der Output Thread arbeitet die Liste dann wieder ab.
Parallel gibt es einen Timer der jede Sekunde DatenKette.GetLive.Value1 ausgibt.

Ok, nun kommt aber der Spannende Teil ... Der TOutputThread ackert nun durch die Liste und jetzt müssen die Daten irgendwie mal in das Chart. Ich habe zu dem Zweck schon mal ein TChart Standard (ist bei jedem Delphi dabei) auf das Formular gepackt.
Ich habe dann testweise mal dem OutputThread das Chart übergeben:
constructor Create(DataClass: TDataClass); Chart : TChart); Und dann im execute folgendes:
Delphi-Quellcode:
            fChart[0].Add(PData2.Value1);
            fChart[1].Add(PData2.Value2);
            fChart[2].Add(PData2.Value3);
            fChart[3].Add(PData2.Value4);
Das funktioniert, aber ich würde mal vermuten das es der falsche Weg ist, denn das wäre ja ein direkter Zugriff vom Thread auf das Chart

Zitat:
Dann also die ValueLists für´s TChart aufbereiten und in einem Synchronize übergeben + zeichnen
Tja da haben wir schon wieder das Problem ... Wenn ich Synchronize nutze, dann wird die Methide im Main Thread ausgeführt. Und genau das möchte ich vermeiden. Denn was passiert wenn der Main Thread (wegen anderer Berechnungen) hängt?
Angehängte Dateien
Dateityp: zip pointerkette_459.zip (6,0 KB, 2x aufgerufen)
Dominik Schmidt
Greetz Dominik

I love Delphi 2007/2010
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.429 Beiträge
 
Delphi 10.4 Sydney
 
#30

Re: Liste (ähnlich dyn Array) mit fortlaufendem Index?

  Alt 29. Mär 2010, 10:48
Zitat von moelski:
Tja da haben wir schon wieder das Problem ... Wenn ich Synchronize nutze, dann wird die Methide im Main Thread ausgeführt. Und genau das möchte ich vermeiden. Denn was passiert wenn der Main Thread (wegen anderer Berechnungen) hängt?
Dann solltest du diese "Berechnungen" auch in einen Thread verschieben.
Wer mit der VCL arbeitet muss damit leben, nur der Hauptthread darf auf Steuerelemente zugreifen.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 3 von 4     123 4      


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 09:53 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