Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   TList mit Record füllen und an weitere TList übergeben (https://www.delphipraxis.net/190069-tlist-mit-record-fuellen-und-weitere-tlist-uebergeben.html)

dGeek 26. Aug 2016 08:49

TList mit Record füllen und an weitere TList übergeben
 
Entweder war ich gestern Abend zu müde oder das was ich vorhabe funktioniert nicht.

Ich habe folgenden Record:
Delphi-Quellcode:
type
 TDataType = (dtFile, dtDirectory);

type
 PFileEntry = ^TFileEntry;

 TFileEntry = packed record
  sFileName: String;
  aDataType: TDataType;
 end;

var
 aProcessFileEntry: PFileEntry;
 aProcessFileList_Record: TList; // Holder
Ich erzeuge mit New() die Datensätze (Records) füge sie der TList mit Add() hinzu.

An einer späteren Stelle muss ich die Liste aussortieren.
Ich erzeuge also eine neue TList und füge gewisse Teile der originalen Liste hinzu:

Delphi-Quellcode:
for j := 0 to iCnt - 1 do
 aTmpFileList_Record.Add(aProcessFileList_Record.Items[j]);
Mein Problem ist jetzt, dass irgendetwas nicht funktioniert und ich schätze mal es liegt an dieser zweiten Liste.
Die zweite Liste hat die korrekte Länge (Count) an Datensätzen aber beim eigentlichen Prozess, wo die Liste benötigt wird, gehts nicht weiter (keine AV, nichts).

Mache ich etwas falsch beim hinzufügen in die aTmpFileList ?

Mavarik 26. Aug 2016 09:32

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von dGeek (Beitrag 1345789)
Ich erzeuge mit New() die Datensätze (Records) füge sie der TList mit Add() hinzu.

Den Record oder den Pointer? Ich hoffe mal den Pointer... :stupid:

Klar kann man noch mit New & Dispose arbeiten.. Aber warum nimmst Du keine Klasse und eine ObjectList mit OwnsValue und schon brauchst Du Dich um nix mehr kümmern...

Mavarik

dGeek 26. Aug 2016 09:37

AW: TList mit Record füllen und an weitere TList übergeben
 
:o

Kannst du mir weiteres dazu erklären?
Das kenne ich noch nicht.

DeddyH 26. Aug 2016 09:43

AW: TList mit Record füllen und an weitere TList übergeben
 
Delphi-Quellcode:
type
  TFileEntry = class
  private
    FFileName: String;
    FDataType: TDataType;
  public
    property FileName: string read FFileName write FFileName;
    property DataType: TDataType read FDataType write FDataType;
  end;
Jetzt kannst Du beliebig viele Instanzen dieser Klasse erzeugen und einer TObjectList hinzufügen. Wenn deren Eigenschaft OwnsObjects true ist (Standard), musst Du die Objekte nicht einmal mehr selbst freigeben, dann kümmert sich die TObjectList selbst darum.

dGeek 26. Aug 2016 09:47

AW: TList mit Record füllen und an weitere TList übergeben
 
Wie erzeuge ich denn Instanzen einer Klasse? Dumme Frage :shock:

Bin jetzt so weit:

Delphi-Quellcode:
type
 TDataType = (dtFile, dtDirectory);

type
 PFileEntry = ^TFileEntry;

 TFileEntry = class(TObject) // <= Object
  sFileName: String;
  aDataType: TDataType;
 end;

type
 TMyClass = class(TComponent)
 public
  FFileEntry: TObjectList;
  constructor Create; overload;
 end;

var
 aProcessFileList_ObjectList: TFileEntry;

implementation

procedure TMyClass.Create; // hier geht es nicht weiter
begin
 FFileEntry := TObjectList.Create;
 FFileEntry.OwnsObjects := true;
end;

DeddyH 26. Aug 2016 10:07

AW: TList mit Record füllen und an weitere TList übergeben
 
Mal ein Beispiel im Editor heruntergetippt:
Delphi-Quellcode:
type
  TFileEntry = class
  private
    FFileName: String;
    FDataType: TDataType;
  public
    property FileName: string read FFileName write FFileName;
    property DataType: TDataType read FDataType write FDataType;
  end;
 
...

procedure TDeinForm.ButtonTestClick(Sender: TObject);
var
  Objects: TObjectList;
  FileEntry: TFileEntry;
  i: integer;
begin
  Objects := TObjectList.Create;
  try
    FileEntry := TFileEntry.Create;
    FileEntry.Filename := 'C:\Dings\Bums\Trallalla.txt';
    FileEntry.DataType := dtFile;
    Objects.Add(FileEntry);
    FileEntry := TFileEntry.Create;
    FileEntry.Filename := 'C:\Dings\Bums';
    FileEntry.DataType := dtDirectory;
    Objects.Add(FileEntry);
    for i := 0 to Objects.Count - 1 do
      ShowMessage((Objects[i] as TFileEntry).Filename);
  finally
    Objects.Free;
  end;
end;

bra 26. Aug 2016 10:31

AW: TList mit Record füllen und an weitere TList übergeben
 
Wozu brauchst du unbedingt den Pointer? Man kann auch den Record einfach so in die Liste reinschmeißen (oder alternativ die Klasse wie von DeddyH beschrieben). Das ganze Pointer-Gedöns würde ich weglassen, wenn es nicht auf triftigen Gründen wirklich notwendig sein sollte.

Mavarik 26. Aug 2016 10:35

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von bra (Beitrag 1345809)
Wozu brauchst du unbedingt den Pointer? Man kann auch den Record einfach so in die Liste reinschmeißen (oder alternativ die Klasse wie von DeddyH beschrieben). Das ganze Pointer-Gedöns würde ich weglassen, wenn es nicht auf triftigen Gründen wirklich notwendig sein sollte.

Das ist hat alte Schule! :thumb:

So hat man das früher eben gemacht...

BTW - Schneller ist es sowieso!!

Mavarik

DeddyH 26. Aug 2016 10:40

AW: TList mit Record füllen und an weitere TList übergeben
 
Die nicht-generische TList enthält aber nun einmal Pointer. Wie willst Du da direkt einen Record reinschreiben?

dGeek 26. Aug 2016 10:41

AW: TList mit Record füllen und an weitere TList übergeben
 
Ich bin zwar ein totaler Nichtskönner was Delphi angeht, mit dem Pointer ist aber leider Angewohnheit.

Danke für eure Hilfe! Eine letzte Frage habe ich aber noch.

Kann es sein, dass
Delphi-Quellcode:
MeineObjectList.Clear;
direkt auc Free igendwo aufruft? Denn nachdem ich
Delphi-Quellcode:
.Clear;
aufgerufen habe, flattert mit eine AV ins Haus wenn ich auf die ObjectList zugreifen möchte.

DeddyH 26. Aug 2016 10:42

AW: TList mit Record füllen und an weitere TList übergeben
 
Clear löscht alle Elemente aus der Liste (und gibt sie ggf. frei), die Liste selbst bleibt aber erhalten.

Mavarik 26. Aug 2016 10:43

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von dGeek (Beitrag 1345813)
Kann es sein, dass
Delphi-Quellcode:
MeineObjectList.Clear;
direkt auch Free igendwo aufruft?

Klar... Das ist ja genau der Trick!

dGeek 26. Aug 2016 10:49

AW: TList mit Record füllen und an weitere TList übergeben
 
Mhhhh kann ich eine ObjectList denn nicht leeren ohne das Object zu zerstören?

Hier knallt es:

Delphi-Quellcode:
// for-Schleife von 0 bis 1
if i > 0 then
 begin
  aTmpFileList_ObjectList.Clear; // <== da knallt es
 end;

DeddyH 26. Aug 2016 10:50

AW: TList mit Record füllen und an weitere TList übergeben
 
OwnsObjects auf false setzen, dann bist Du selbst verantwortlich.

p80286 26. Aug 2016 11:15

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von Mavarik (Beitrag 1345816)
Zitat:

Zitat von dGeek (Beitrag 1345813)
Kann es sein, dass
Delphi-Quellcode:
MeineObjectList.Clear;
direkt auch Free igendwo aufruft?

Klar... Das ist ja genau der Trick!

Bittää?
Das wäre doch ein sehr überraschender Effekt. Wenn ein .Delete() oder ein .Clear ein .Free des ListenItems nach sich zieht ok, aber ein .Free auf die Liste??

Gruß
K-H

P.S.
die sieben Zeilen um in ein .Delete ein Dispose für den Pointer zu packen ist ja nun nicht DER Aufwand.

Aviator 26. Aug 2016 11:18

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von p80286 (Beitrag 1345824)
Zitat:

Zitat von Mavarik (Beitrag 1345816)
Zitat:

Zitat von dGeek (Beitrag 1345813)
Kann es sein, dass
Delphi-Quellcode:
MeineObjectList.Clear;
direkt auch Free igendwo aufruft?

Klar... Das ist ja genau der Trick!

Bittää?
Das wäre doch ein sehr überraschender Effekt. Wenn ein .Delete() oder ein .Clear ein .Free des ListenItems nach sich zieht ok, aber ein .Free auf die Liste??

Tut es ja nicht. Ich würde behaupten er hat sich nur falsch ausgedrückt oder zu schnell geschrieben. Die Liste selbst bleibt durch ein Clear selbstverständlich erhalten. Nur die Items darin werden (sofern OwnsObjects auf True) freigegeben. OwnsObjects kann mein Create oder aber auch nachträglich als Eigenschaft der Liste auf False bzw. True gesetzt werden.

dGeek 26. Aug 2016 13:27

AW: TList mit Record füllen und an weitere TList übergeben
 
Scheinbar mag mich die Object-List nicht.

Kurze erklärung:
ich habe eine Liste von Dateien.
Die speichere ich mit noch ein paar anderen Informationen in diese "Instanzen" von TFileEntry ab.
Alle Instanzen kommen dann in ObjectList-A.

Nun gehe ich diese ObjectList-A durch und teile sie in n-Stückchen auf. Mit diesen Stücken werden Threads gefüttert und gestartet.
Bei 100 Instanzen erhält bei 5 Threads jeder Threads also 20 Instanzen, die er abarbeiten soll.

Mein einfacher Test:
es gibt 10 Instanzen und 2 Threads. 5 Pro Thread.

jetzt das Seltsame: beide Threads bekommen dieselbe Instanz!

Meine Logik ist also:
- Dateiliste erstellen
- Für jede Datei 1 Instanz von TFileEntry erstellen
- alle Instanzen in die ObjectList-A

Nun ObjectList-A.Count durch die Anzahl der Threads teilen. Ergibt 5 Instanzen pro Thread / 2 Threads.
Diese 5 Instanzen werden in eine temporäre ObjectList-B geschrieben, die kurz vorher außerhalb der for-schleife erzeugt wird.
Am ende der for-Schleife übergebe ich ObjectList-B an eine Procedur wo nichts weiter drin steht als, dass ein TThread erzeugt werden soll. Er hat ein Property und das ist eine ObjectList.

Aviator 26. Aug 2016 13:38

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von dGeek (Beitrag 1345831)
Scheinbar mag mich die Object-List nicht.

Kurze erklärung:
ich habe eine Liste von Dateien.
Die speichere ich mit noch ein paar anderen Informationen in diese "Instanzen" von TFileEntry ab.
Alle Instanzen kommen dann in ObjectList-A.

Nun gehe ich diese ObjectList-A durch und teile sie in n-Stückchen auf. Mit diesen Stücken werden Threads gefüttert und gestartet.
Bei 100 Instanzen erhält bei 5 Threads jeder Threads also 20 Instanzen, die er abarbeiten soll.

Mein einfacher Test:
es gibt 10 Instanzen und 2 Threads. 5 Pro Thread.

jetzt das Seltsame: beide Threads bekommen dieselbe Instanz!

Meine Logik ist also:
- Dateiliste erstellen
- Für jede Datei 1 Instanz von TFileEntry erstellen
- alle Instanzen in die ObjectList-A

Nun ObjectList-A.Count durch die Anzahl der Threads teilen. Ergibt 5 Instanzen pro Thread / 2 Threads.
Diese 5 Instanzen werden in eine temporäre ObjectList-B geschrieben, die kurz vorher außerhalb der for-schleife erzeugt wird.
Am ende der for-Schleife übergebe ich ObjectList-B an eine Procedur wo nichts weiter drin steht als, dass ein TThread erzeugt werden soll. Er hat ein Property und das ist eine ObjectList.

Zeig mal etwas SourceCode. Dann wird es vmtl. einfacher dir zu helfen. :cyclops:

Ich könnte mir vorstellen wo dein Fehler ist, aber ich will nicht wild drauf losraten. :stupid:

dGeek 26. Aug 2016 13:51

AW: TList mit Record füllen und an weitere TList übergeben
 
Ihr werdet mich für den Code HASSEN :lol: (poste ich gleich aber erst eine Frage).

Ich habe mittlerweile herausgefunden, dass wenn ich nach der Procedur die den Thread erstellt eine Showmessage mache, alles korrekt abläuft. Scheint also ein sehr suspektes Zeitproblem zu sein.

geht deine Vermutung in diese Richtung?

Aviator 26. Aug 2016 13:59

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von dGeek (Beitrag 1345835)
geht deine Vermutung in diese Richtung?

Nein eher nicht. :wink: Es kann natürlich sein, das ich mit meiner Vermutung total falsch liege.

Zitat:

Zitat von dGeek (Beitrag 1345835)
Ihr werdet mich für den Code HASSEN :lol:

Jeder hat doch mal klein angefangen. Als ich das erste Mal mit ObjectLists gearbeitet hatte, ging auch nicht alles direkt. Heute will ich sie nicht mehr missen. Da hakte es auch an der ein oder anderen Stelle. Und die Formatierung des SourceCodes kannst du ja schnell durch die IDE machen lassen falls du das meinst. :-D

stahli 26. Aug 2016 14:03

AW: TList mit Record füllen und an weitere TList übergeben
 
Dein Problem ist offenbar nicht mehr die TList sondern die Synchronisierung von Threads.

In dem Fall wäre das dann auch ein Thema für einen neuen "Thread". ;-)

Hier gab es kürzlich eine nette Zusammenfassung: https://www.youtube.com/watch?v=Jhcpgjs1uPA

dGeek 26. Aug 2016 14:05

AW: TList mit Record füllen und an weitere TList übergeben
 
Ich habe alles Unwichtige rausgenommen und ein bisschen Pseudo-Kommentiert, damit man es HALBWEGS nachvollziehen kann :lol:
Threads sind nicht das Problem. Denn als ich das alles ohne ObjectList hatte, lief es einwandfrei.

Delphi-Quellcode:
// aProcessFileList_ObjectList enthält "10" Instanzen von TFileEntry
// aProcessFileList_ObjectList.OwnsObjects ist "False"
// aGlobalVars.iMaxCopyThreadCount ist "2"
// iFilesPerThread ist "5"

// Der ganze StringList-Kram ist nur zum TEST da

{*
 Dateien z.B.:
 
 - Datei0.txt
 - Datei1.txt
 - Datei2.txt
 - Datei3.txt
 - Datei4.txt
 - Datei5.txt
 - Datei6.txt
 - Datei7.txt
 - Datei8.txt
 - Datei9.txt
*}
 
aTmpFileList_ObjectList := TObjectList.Create;
aTmpFileList_ObjectList.OwnsObjects := False;
 
try
 for i := 0 to aGlobalVars.iMaxCopyThreadCount - 1 do
  begin
   Application.ProcessMessages;

   try
    if aProcessFileList_ObjectList.Count >= iFilesPerThread then
     begin
      // Liste wird geleert, damit nicht die alten Daten drin sind / SEIN SOLLTEN
      aTmpFileList_ObjectList.Clear;

      iCnt := iFilesPerThread;

      if aProcessFileList_ObjectList.Count - iCnt = 1 then
       Inc(iCnt);

      {*
        Erster Durchgang: aTmpFileList_ObjectList bekommt "Datei0" bis "Datei4"
        Zweiter Durchgang: aTmpFileList_ObjectList bekommt "Datei5" bis "Datei9"
      *}
      for j := 0 to iCnt - 1 do
       aTmpFileList_ObjectList.Insert(j, aProcessFileList_ObjectList.Items[j]);

      sl := TStringList.Create;
      try
       {*
         Erster Durchgang: aus aProcessFileList_ObjectList wird "Datei4" bis "Datei0" gelöscht
         Zweiter Durchgang: aus aProcessFileList_ObjectList wird "Datei9" bis "Datei5" gelöscht
       *}
       for j := iCnt - 1 downto 0 do
        begin
         aProcessFileList_ObjectList.Delete(j);
         sl.Add(TFileEntry(aTmpFileList_ObjectList.Items[j]).sSourceDirItem);
        end;

       // StringList-TEST - was ist in der Liste? In eine Datei abspeichern!
       sl.SaveToFile(ExtractFilePath(ParamStr(0)) + '__DELETE' + IntToStr(i) + '.txt');
      finally
       sl.Free;
      end;

     
      sl := TStringList.Create;
      try
       for j := 0 to aTmpFileList_ObjectList.Count - 1 do
        begin
         sl.Add(TFileEntry(aTmpFileList_ObjectList.Items[j]).sSourceDirItem);
        end;
       
       // StringList-TEST - was ist in der Liste? In eine Datei abspeichern!
       sl.SaveToFile(ExtractFilePath(ParamStr(0)) + '__' + IntToStr(i) + '.txt');
      finally
       sl.Free;
      end;

      if aTmpFileList_ObjectList.Count > 0 then
       begin
        {*
          Erster Durchgang: Thread1 arbeitet "Datei0" bis "Datei4" ab
          Zweiter Durchgang: Thread2 arbeitet "Datei5" bis "Datei9" ab
        *}
        createCopyThread(aTmpFileList_ObjectList);
       end;
     end
    else
     break;
   except
    // ...
   end;
  end;

  // Wenn noch RESTE in der originalen ObjectList sind, dann erstelle damit einen seperaten Thread
  // Das ist z.B. der Fall, wenn 11 Dateien verarbeitet werden müssten. Die letzte (elfte) Datei würde hier in einen Thread gepackt werden
  if aProcessFileList_ObjectList.Count > 0 then
   begin
    createCopyThread(aProcessFileList_ObjectList);
   end;
  end;
finally
 aTmpFileList_ObjectList.Free;
end;

////////////////////////////////////////////////////////////////////////////////

procedure createCopyThread(FaFileList: TObjectList);
 var
  aCopyThread: TCopyThread;
 begin
  aCopyThread := TCopyThread.Create;

  aCopyThread.aFileList := FaFileList;
 end;

////////////////////////////////////////////////////////////////////////////////

type
 TCopyThread = class(TThread)
 private
  { Private-Deklarationen }
  FaFileList: TObjectList;
 protected
  procedure Execute; override;
 public
  { Public-Deklarationen }
  constructor Create;
  procedure Finish(Sender: TObject);

  property aFileList: TObjectList read FaFileList write FaFileList;
 end;

DeddyH 26. Aug 2016 14:10

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von dGeek (Beitrag 1345841)
Threads sind nicht das Problem.

Bist Du da ganz sicher? Du musst bedenken, dass der Code, der nach dem Erzeugen der Threads kommt, auch weiter ausgeführt wird, während die Threads noch laufen.

dGeek 26. Aug 2016 14:12

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von DeddyH (Beitrag 1345842)
Zitat:

Zitat von dGeek (Beitrag 1345841)
Threads sind nicht das Problem.

Bist Du da ganz sicher? Du musst bedenken, dass der Code, der nach dem Erzeugen der Threads kommt, auch weiter ausgeführt wird, während die Threads noch laufen.

Das weiß ich, keine Sorge. Deswegen benutze ich Threads ja :P

Aber ich übergebe dem Thread doch die ObjectList. Hat der dann nicht eine vollkommen eigene Kopie davon? Und wenn ich dann das Original (aTmpFileList_ObjectList) ändere, dürfte das die Daten im Thread doch nicht ändern.

bra 26. Aug 2016 14:24

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von dGeek (Beitrag 1345844)
Aber ich übergebe dem Thread doch die ObjectList. Hat der dann nicht eine vollkommen eigene Kopie davon? Und wenn ich dann das Original (aTmpFileList_ObjectList) ändere, dürfte das die Daten im Thread doch nicht ändern.

Klassen werden als Pointer übergeben, d.h. dein Thread arbeite mit derselben Liste, wie im Hauptthread. Wenn du die Liste also im Thread oder im Hauptthread veränderst, wirkt sich das überall aus.
Du könntest den Aufruf beim Thread als const definieren, dann wird eine Kopie deiner Liste erstellt:

Delphi-Quellcode:
procedure createCopyThread(const FaFileList: TObjectList);
...

DeddyH 26. Aug 2016 14:26

AW: TList mit Record füllen und an weitere TList übergeben
 
Wieso sollte da eine Kopie erstellt werden?

Aviator 26. Aug 2016 14:29

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von bra (Beitrag 1345845)
Zitat:

Zitat von dGeek (Beitrag 1345844)
Aber ich übergebe dem Thread doch die ObjectList. Hat der dann nicht eine vollkommen eigene Kopie davon? Und wenn ich dann das Original (aTmpFileList_ObjectList) ändere, dürfte das die Daten im Thread doch nicht ändern.

Klassen werden als Pointer übergeben, d.h. dein Thread arbeite mit derselben Liste, wie im Hauptthread.

Genau das war auch meine Vermutung @dGeek. Du übergibst dem Thread eine Instanz einer ObjectList und verwendest diese dann weiter. Du müsstest dir pro Durchlauf deiner äußersten Schleife eine neue Instanz der ObjectList erstellen. Die kannst du dann auch bedenkenlos nach Beendigung des Threads im Thread freigeben lassen.

Des Weiteren könntest du auch folgenden machen:

Delphi-Quellcode:
aTmpFileList_ObjectList := TObjectList<TFileEntry>.Create(False);
.

Das hat 2 Vorteile:
  • Du brauchst nicht mehr zu casten, sondern bekommst beim Auslesen deiner ObjectList direkt ein Object vom Typ TFileEntry zurück
  • Der False Parameter bewirkt, dass OwnsObjects beim Erzeugen deiner Liste auf False gesetzt wird (somit entfällt die zweite Zeile)

dGeek 26. Aug 2016 14:31

AW: TList mit Record füllen und an weitere TList übergeben
 
Das mit dem Zeiger wusste ich nicht. Ich dachte die ObjectList wird ganz normal übergeben und die Procedur hat dann davon eine Kopie.
Klingt jetzt verdächtig nach einem Array von ObjectListen wenn ich das richtig verstanden habe?



Ihr seid so genial :-D
Es funktioniert nun. Ich packe nun alle Instanzen in ObjectLists, die bei Gebraucht erzeugt werden. Verwaltet werden sie in einem dynamischen Array of TObjectList.

Aviator 26. Aug 2016 14:45

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von dGeek (Beitrag 1345849)
Klingt jetzt verdächtig nach einem Array von ObjectListen wenn ich das richtig verstanden habe?

Das verstehe ich jetzt nicht. :roll:

Hier mal ein Beispiel wie ich es machen würde (ungetestet und nur hier runtergetippt):

Delphi-Quellcode:
 
try
  for i := 0 to aGlobalVars.iMaxCopyThreadCount - 1 do
   begin
    Application.ProcessMessages; // <--- Das hier brauchst du normalerweise nicht, da die Aktion so schnell abläuft, dass du davon sehr wahrscheinlich nichts mitbekommst

    try
      if aProcessFileList_ObjectList.Count >= iFilesPerThread then
      begin
        aTmpFileList_ObjectList := TObjectList<TFileEntry>.Create(False); // <--------------  ObjectList erst hier erzeugen. Somit kommen die sich nicht in die Quere.
        // aTmpFileList_ObjectList.OwnsObjects := False; // Durch den False Parameter entfällt diese Zeile

        // Liste wird geleert, damit nicht die alten Daten drin sind / SEIN SOLLTEN
        // aTmpFileList_ObjectList.Clear; // Das hier brauchst du normal auch nicht, da eine Liste beim Erstellen immer leer ist/sein sollte

        iCnt := iFilesPerThread;

        if aProcessFileList_ObjectList.Count - iCnt = 1 then
          Inc(iCnt);

      {*
        Erster Durchgang: aTmpFileList_ObjectList bekommt "Datei0" bis "Datei4"
        Zweiter Durchgang: aTmpFileList_ObjectList bekommt "Datei5" bis "Datei9"
      *}
        for j := 0 to iCnt - 1 do
          aTmpFileList_ObjectList.Add(aProcessFileList_ObjectList.Items[j]);

        CreateWorkingThread(aTmpFileList);
      end;
    finally
      // Blubb
    end;
  end;
finally

end;

Delphi-Quellcode:
procedure TWorkingThread.Execute;
begin
  // Do something here
  FTmpFileList.Free; // Hier die beim Erzeugen des Threads übergebene ObjectList freigeben
end;
Nicht hauen, wenn ich jetzt etwas vergessen oder mich irgendwo vertippt habe. :-D

stahli 26. Aug 2016 14:47

AW: TList mit Record füllen und an weitere TList übergeben
 
Die Prozedur erhält eine Referenz auf die Objektliste.
Sie benutzt also die gleiche Liste.

Eine Kopie der Liste könntest Du erzeugen, wenn Du eine neue Listeninstanz erzeugst und die Einträge kopierst.

Wenn die Einträge Objekte sind, kopierst Du aber auch nur wieder Referenzen auf die Listeneinträge.

Du kannst das analog
Delphi-Quellcode:
Panel2 := Panel1
sehen.
Hier wird der Variablen Panel2 ja auch nur eine andere Referenz (ein anderer Pointer) zugewiesen.


PS: Sehe gerade, dass Du es gelöst hast.
Aber Dein "Array of ObjectList" kann ich nicht ganz nachvollziehen.
Egal, wenn es läuft, läuft es :-)
Vielleicht kannst Du es ja später nochmal anders ordnen.

DeddyH 26. Aug 2016 14:50

AW: TList mit Record füllen und an weitere TList übergeben
 
Ich kapier es auch nicht. IMO ist der Knackpunkt, dass da in derselben Methode Threads erzeugt werden, die eine Objektliste zugewiesen bekommen, und diese Objektlisten gleich danach wieder freigegeben werden. Das dürfte den Thread nicht erfreuen, wenn er mitten in der Arbeit auf einen Dangling Pointer stößt.

Aviator 26. Aug 2016 14:51

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von stahli (Beitrag 1345856)
Wenn die Einträge Objekte sind, kopierst Du aber auch nur wieder Referenzen auf die Listeneinträge.

Das stimmt. Eigentlich müsste er sich seine Daten von TPersistent ableiten und die Assign Methode überschreiben. Dann hätte er keine gleichen Referenzen mehr und ein löschen/freigeben der Liste würde ihm nicht plötzlich alles um die Ohren fliegen lassen.

p80286 26. Aug 2016 14:56

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von stahli (Beitrag 1345856)
Aber Dein "Array of ObjectList" kann ich nicht ganz nachvollziehen.

wenigstens das scheint mir einleuchtend

SQL-Code:
Anzhappen:=Wieviele_Teile_in_Liste(FNList);
set length(LA,Anzhappen);
for i:=0 to anzhappen-1 do begin
   LA[i]:=Tmpliste.create
   fülle(FNListe,LA[i]);
end;

For i:=0 to Anzhappen do
  machThread;

So ungefähr sollte das Laufen.

Gruß
K-H

p80286 26. Aug 2016 15:06

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von Aviator (Beitrag 1345858)
Zitat:

Zitat von stahli (Beitrag 1345856)
Wenn die Einträge Objekte sind, kopierst Du aber auch nur wieder Referenzen auf die Listeneinträge.

Das stimmt. Eigentlich müsste er sich seine Daten von TPersistent ableiten und die Assign Methode überschreiben. Dann hätte er keine gleichen Referenzen mehr und ein löschen/freigeben der Liste würde ihm nicht plötzlich alles um die Ohren fliegen lassen.

Wisst Ihr was das schöne an Pointern ist?
Da weiß man was man benutzt!

Gruß
K-H

Aviator 26. Aug 2016 15:08

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von p80286 (Beitrag 1345859)
Zitat:

Zitat von stahli (Beitrag 1345856)
Aber Dein "Array of ObjectList" kann ich nicht ganz nachvollziehen.

wenigstens das scheint mir einleuchtend

SQL-Code:
Anzhappen:=Wieviele_Teile_in_Liste(FNList);
set length(LA,Anzhappen);
for i:=0 to anzhappen-1 do begin
   LA[i]:=Tmpliste.create
   fülle(FNListe,LA[i]);
end;

For i:=0 to Anzhappen do
  machThread;

So ungefähr sollte das Laufen.

Gruß
K-H

Wenn er die Instanz der ObjectList an den Thread weitergibt, dann brauch er sich diese nicht mehr zu merken. Die soll ja eh temporär sein. Dann kann der Thread beim Verlassen der Execute Methode auch gerade noch die ObjectList ins Nirvana wandern lassen.

Dann braucht er auch kein Array mehr mitzuschleppen in dem Dann u.U. die Instanzen noch hängen bleiben.

Mavarik 26. Aug 2016 15:45

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von dGeek (Beitrag 1345835)
Ihr werdet mich für den Code HASSEN :lol:

Hassen - nein - nur viel zu umständlich - aber da Du in Deinem Profil nicht angegeben hast, welche Delphi Version Du nutzt, gehe ich davon aus, diese ist kleine XE6, oder?

dGeek 26. Aug 2016 16:00

AW: TList mit Record füllen und an weitere TList übergeben
 
Das Geld reicht nur für XE2.
Umständlich ist mein zweiter Vorname.

Ich habe erst letztens noch eine Funktion komplett neugeschrieben. Sie wurde insgesamt sehr viel schneller.
Bei 1.000.000 Aufrufen spare ich 200ms.

Ich brauche diese Funktion exakt ein einziges mal in meinem Code. Hat sich demnach also gelohnt :thumb:

Mavarik 26. Aug 2016 16:15

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von dGeek (Beitrag 1345866)
Das Geld reicht nur für XE2.

Free Starter 10.1? :stupid: Egal...

OK Dann fällt alles mit der Parallel Library weg...

Ich würde für sowas eine parallel-multithreding-pipeline nehmen, denn während Du die Files ermittelst, könnte
der 1. Task schon los legen und die Daten verarbeiten...

Also eine Threadsave Queue verwenden in die Du die einzelnen File-Record-Classen rein pumpst...
Am besten die Klasse als
Delphi-Quellcode:
TFileData = Class(TInterfacedObject,ICanHandeFileData)
aufbauen und nur die Interfaces in die Queue packen...

Dann können sich N-Thread daraus bedienen und brauchen einfach nur das Interface los zu lassen...
Da die Klasse referenzcounted ist, ist auch Dein Speicher wieder sauber...

Mavarik :coder:

p80286 26. Aug 2016 17:29

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

Zitat von Mavarik (Beitrag 1345869)
Also eine Threadsave Queue verwenden in die Du die einzelnen File-Record-Classen rein pumpst...
Am besten die Klasse als
Delphi-Quellcode:
TFileData = Class(TInterfacedObject,ICanHandeFileData)
aufbauen und nur die Interfaces in die Queue packen...

Dann können sich N-Thread daraus bedienen und brauchen einfach nur das Interface los zu lassen...
Da die Klasse referenzcounted ist, ist auch Dein Speicher wieder sauber...

Klingt wie threadsaver FiFo-Stack gibt's so etwas oder muß man da selbst Hand anlegen?

Gruß
K-H

dGeek 26. Aug 2016 20:49

AW: TList mit Record füllen und an weitere TList übergeben
 
Zitat:

denn während Du die Files ermittelst, könnte der 1. Task schon los legen und die Daten verarbeiten...
So ist es doch aktuell auch schon.


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:45 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