Rekursion in einem Thread: Dateisuche

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Socke
Lazarusforum e. V.
Beiträge: 3181
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Rekursion in einem Thread: Dateisuche

Beitrag von Socke »

Hallo,

Um mein GUI nicht unnötig zu blockieren, möchte ich das rekursive Auslesen einer Verzeichnisstruktur in einen Thread auslagern. Die Thread-Methode Execute ruft folgende Methode SearchFiles auf.

Code: Alles auswählen

procedure TMySearchThread.SearchFiles(aRoot: String);
var
  search: TSearchRec;
begin
  if FindFirstUTF8(aRoot+'*',faDirectory,search) = 0 then
  try
    repeat
      if (search.Attr and faDirectory) = faDirectory then
        SearchFiles(IncludeTrailingPathDelimiter(aRoot+search.Name))
      else
      begin
        // sync with main thread
        FFile := aRoot+search.Name;
        // call event handler
        Synchronize(@MTSyncProc);
      end;
    until Terminated or (FindNextUTF8(search) <> 0);
  finally
    FindCloseUTF8(search);
  end;
end;
Wird dieser Thread erstellt und ausgeführt, werden einige Speicherbereiche nicht wieder freigegeben. Die Unit heaptrc liefert die Blockgrößen 41, 16 und 60 Byte und einige Speicheradresse, mit denen ich nichts weiter anfangen kann. Die 60 Byte schiebe ich auf das Thread-Objekt, welches genau diese Größe aufweist. Anscheinend wird er nicht korrekt beendet und durch FreeOnTerminate freigegeben. Ersetze ich den Rekursionsaufruf durch einen neuen Thread (selbe Klasse), läuft alles wunderbar durch und alles wird auch wieder freigegeben.
Die Synchronisation zwischen diesem und dem Main-Thread ist bisher noch nicht vollständig implementiert (d.h. nicht überprüfbar).

Eine solche Rekursion habe ich auch bereits an anderer Stelle gefunden, auch wenn nicht auf Threads bezogen. Die Variante mit neuen Threads möchte ich eher ungern verwenden, auch wenn die Anzahl an Verzeichnissen und Dateien in der Regel sehr begrenzt ist (ca. 5 Verzeichnisse mit jeweils 3 Ebenen). Ich kann mir nur schlecht vorstellen, dass hier bisher noch niemand so etwas versucht hat. Gibt es also eine Möglichkeit die Rekursion auf einen Thread zu beschränken?
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1746
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Rekursion in einem Thread: Dateisuche

Beitrag von corpsman »

Code: Alles auswählen

if (search.Attr and faDirectory) = faDirectory then
        SearchFiles(IncludeTrailingPathDelimiter(aRoot+search.Name))
      else
Müste das nicht :

Code: Alles auswählen

if (search.Attr and faDirectory) = faDirectory then begin
  if (search.name <> '.') and (search.name <> '..') then 
        SearchFiles(IncludeTrailingPathDelimiter(aRoot+search.Name));
  end else
heisen ?

Zumindest ist das bei mir immer so, ..
--
Just try it

Scotty
Beiträge: 768
Registriert: Mo 4. Mai 2009, 13:24
OS, Lazarus, FPC: Arch Linux, Lazarus 1.3 r44426M FPC 2.6.4
CPU-Target: x86_64-linux-qt/gtk2
Kontaktdaten:

Re: Rekursion in einem Thread: Dateisuche

Beitrag von Scotty »

Um mein GUI nicht unnötig zu blockieren, möchte ich das rekursive Auslesen einer Verzeichnisstruktur in einen Thread auslagern.
Selbst bei 1000+ Dateien in einem Verzeichnis braucht mein PC keine Sekunde zum Auslesen. Was für einen abscheulichen Missbrauch der Hardware betreibst du denn (bzw. musst du betreiben), dass diese Sache gethreaded werden müsste? :shock:
Ansonsten: Heaptrace und Threads vertragen sich IMHO nicht miteinander. Ich habe da auch immer ein paar Bytes übrig.

Benutzeravatar
theo
Beiträge: 11207
Registriert: Mo 11. Sep 2006, 19:01

Re: Rekursion in einem Thread: Dateisuche

Beitrag von theo »

Ich sehe das ähnlich wie Scotty.
V.a. für jeden Dateinamen einmal mit dem MainThread synchronisieren ist ziemlich ineffizient.
Wenn du den Thread wirklich benötigst, würde ich in der Threadklasse eine Liste füllen und diese vom MainThread aus OnTerminate auslesen oder so.

marcov
Beiträge: 1104
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Rekursion in einem Thread: Dateisuche

Beitrag von marcov »

Scotty hat geschrieben:
Um mein GUI nicht unnötig zu blockieren, möchte ich das rekursive Auslesen einer Verzeichnisstruktur in einen Thread auslagern.
Selbst bei 1000+ Dateien in einem Verzeichnis
1000+ ist viel? Ich habe hier eine Million Bilder in ein Verzeichnis :-)

Socke
Lazarusforum e. V.
Beiträge: 3181
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Rekursion in einem Thread: Dateisuche

Beitrag von Socke »

corpsman hat geschrieben:

Code: Alles auswählen

if (search.Attr and faDirectory) = faDirectory then begin
  if (search.name <> '.') and (search.name <> '..') then 
        SearchFiles(IncludeTrailingPathDelimiter(aRoot+search.Name));
  end else
Danke, damit funktioniert es! Ich hab nur die zweite if-Abfrage in die erste mit integriert.

Dann noch ein paar Kommentare zu euren sonstigen Kommentaren:
Scotty hat geschrieben:Selbst bei 1000+ Dateien in einem Verzeichnis braucht mein PC keine Sekunde zum Auslesen. Was für einen abscheulichen Missbrauch der Hardware betreibst du denn (bzw. musst du betreiben), dass diese Sache gethreaded werden müsste? :shock:
Ich könnte selbstverständlich alles im Mainthread verarbeiten, aber man wird doch noch lernen dürfen :D
Eines meiner Testverzeichnisse (mit den meisten Dateien) enthält 289 Dateien - also recht wenig. time ls -lR > /dev/null benötigt dafür 0,003 Sekunden, wovon 0,004 Sekunden im Kernel ausgeführt werden.
Scotty hat geschrieben:Ansonsten: Heaptrace und Threads vertragen sich IMHO nicht miteinander. Ich habe da auch immer ein paar Bytes übrig.
Ein anderer Thread, der nur ein Verzeichnis durchsucht (nicht rekursiv), funktioniert tadellos und auch heaptrc gibt keine Fehler aus.

Der Grund, warum ich einen Thread haben will, ist, dass zeitgleich eine XML-Datei ausgewertet werden soll. Diese enthält im Idealfall alle im gescannten Verzeichnis enthaltenen Dateien. Möglicherweise gibts aber auch Unterschiede, und die sollen dann dargestellt werden. Allein das Iterieren über den Abschnitt der XML-Datei (also nur der relevante Teil) dauert 5 Sekunden mit DOM. Deshalb hatte ich an zwei Threads gedacht: einen für die XML-Datei und einen für die Festplatte.
theo hat geschrieben:Ich sehe das ähnlich wie Scotty.
V.a. für jeden Dateinamen einmal mit dem MainThread synchronisieren ist ziemlich ineffizient.
Wenn du den Thread wirklich benötigst, würde ich in der Threadklasse eine Liste füllen und diese vom MainThread aus OnTerminate auslesen oder so.
Es war eher zur Veranschaulichung für den Benutzer gedacht; Ich werde das aber noch einmal überdenken, da die Dateinamen auch noch zur Anzeige aufbereitet werden sollen.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Antworten