Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Threads verwalten (https://www.delphipraxis.net/143693-threads-verwalten.html)

David Martens 21. Nov 2009 00:17


Threads verwalten
 
Ich bin dabei ein Programm zu schreiben das verschiedene Dateien auf Änderungen überwacht. Jetzt will ich das aber in verschiedenen Threads machen. Meine Frage wie?

ein Thread soll haben:
- 1 Komponente zur Überwachung (TfisFileNotification)
- 1 Komponente zur Speicherung (Versionierung) der Änderung (TJvZlibMultiple)
- dirverse einfache Variablen wie:
Delphi-Quellcode:
   
    Name,
    WatchFolder,
    BackupFolder  : string;

    IncludeFiles,
    ExcludeFiles,
    ExcludeFolder : string;
    minSize,
    maxSize       : integer;
Nun weiß ich aber im Vorfeld nicht wieviele Threads ich brauche. Ich dachte da an eine TObjectList am besten eine typisierte (siehe hier).

Da ich aber noch nicht so tief in die Materie eingestiegen bin wollte ich wissen wie ich Threads in eine Liste verwalten kann.
Die Threads sind von Natur aus (vielleicht bis auf die, von mir gewünschten, Meldungen fürs Log) unabhänig. Da habe ich schon was gefunden mit
Delphi-Quellcode:
PostMessage(MainForm.Handle, MY_WM_USER, SUB_MESSAGE_X, Integer(InfoRecord));
kann ich aus den einzelnen Threads die Log füllen.

Was ich jetzt noch wissen muß wie muß die Threadklasse aussehen, wie kann ich die zur Laufzeit erzeugen und wie verwalte ich die in der Liste?

Ich hoffe ich habe mich verständlich ausgedrückt und falls das alles Quatsch ist, was ich geschrieben habe dann entschuldige ich mich schonmal.

Danke
David

sirius 22. Nov 2009 15:08

Re: Threads verwalten
 
Hmm, ist ja eine sehr allgemeine Frage.

Also, ja Du kannst viele Threads erzeugen und ale einer Objectliste hinzufügen. Ob du die Liste typisieren musst, liegt an dir und der Aufgabe selbst.

Die Übergabe des Ergebnisses würde per Postmessage gehen, aber dazu muss InfoRecord extern auf dem Heap liegen, oder du verwnedest sendmessage.

taaktaak 22. Nov 2009 15:16

Re: Threads verwalten
 
PostMessage und SendMessage verwende ich auch sehr oft, darf ich da mal eine Zwischenfrage stellen:
Wie erreiche ich, dass InfoRecord auf dem Heap eingerichtet wird und damit PostMessage verwendet werden kann? Wird eine Unit-lokale Variable im Heap angelegt?

Apollonius 22. Nov 2009 15:21

Re: Threads verwalten
 
Nein, eine Unit-lokale Variable ist ja auch global. Das Problem daran ist, dass es die Variable nur einmal gibt - du musst also sicherstellen, dass du nicht die Daten überschreibst, bevor der Hauptthread sie abgeholt hat. Für den Heap brauchst du New und Dispose bzw. GetMem und FreeMem.

himitsu 22. Nov 2009 15:24

Re: Threads verwalten
 
unitlokal/global = heap
prozedurlokal = stack

du mußt aber aufpassen, daß der Speicher nicht wieder überschrieben wird.

z.B. mehrmals PostMessage mit diesem Speicher, aber das "Ziel" hat die gesendeten Nachrichten noch garnicht verarbeitet und somit würde der Speicher zurüh überschrieben.

Du kannst aber z.B. mit GetMem Speicher reservieren, mit PostMessage versenden und am "Ziel" diesen Speicher dann wieder freigeben.
(aber Achtung: einige Speichermanager muß man erst in einen Threadsicheren Modus versetzen, aber ich hoffe mal, daß dieses bei dir schon der Fall ist)

Apollonius 22. Nov 2009 15:27

Re: Threads verwalten
 
Hm? "Heap" ist doch normalerweise nur der Bereich, der vom Speichermanager verwaltet wird, und das ist bei globalen Variablen nicht der Fall. Kann aber sein, dass ich mich hier in der Terminologie irre.

taaktaak 22. Nov 2009 15:35

Re: Threads verwalten
 
Danke, bisher funktioniert das alles recht gut!
Meine Anwendungsfälle sind allerdings nicht thread-bezogen, ich verwende das Verfahren um Nachrichten zwischen Units auszutauschen, die sich nicht kennen. So versendet z.B. die Konfiguration eine neu gesetzte Farbe und alle Units, die sich berufen fühlen, aktualisieren dann ausgewählte Controls.

Äh, ja, ein Widerspruch ist da.
Würde aber aufgrund fehlender Fehler (hihi) zu himitsu's Erklärung tendieren

David Martens 22. Nov 2009 23:49

Re: Threads verwalten
 
Um auf die ursprüngliche Frage zurückzukommen, ja die Frage ist sehr allgemein.

So weit ich jetzt verstanden habe kann ich also eine Klasse wie die erstellen:
Delphi-Quellcode:
TWatchThread = class(TThread)
private
  FileNotify : TfisFileNotification;
  FileZip   : TJvZlibMultiple;

  Name,
  WatchFolder,
  BackupFolder  : string;
  IncludeFiles,
  ExcludeFiles,
  ExcludeFolder : string;
  minSize,
  maxSize       : integer;

  procedure OnNotifyChanged(Sender: TObject);
public
  constructor Create(AOwner : TComponent);
 
  procedure Execute; override;
end;

procedure TWatchThread.Execute;
begin
  FileNotify.Start;
  ...
  FlieNotify.OnChanged := OnNotifyChanged;
end;

procedure TWatchThread.OnNotifyChanged(Sender: TObject);
begin
  // auf den Event reagieren
  // Liste der Dateien durchgehen, Änderungen mit FileZip speichern
 
  // So hier die Meldung für das Log ???
  PostMessage(MainForm.Handle, MY_WM_USER, SUB_MESSAGE_NEW_SAVE, Integer(InfoRecord));
end;
Und dann kann ich die TWatchThread Objekte einfach in eine TObjectList speichern?

Delphi-Quellcode:
// Threads erstellen
begin
  ObjectList := TObjectList.Create;
  ObjectList.OwnsObjects := true;

  // für alle zu überwachende Verzeichnisse
  ObjectList.Add(TWatchThread.Create(Self));
end;

// Threads starten
begin
  aWatchThread := TWatchThread(ObjectList.Items[index]);
  aWatchThread.Execute;
end;
Ich muß natürlich noch auf die Messages reagieren, aber hab ich das so richtig gemacht?

Danke David

himitsu 23. Nov 2009 07:31

Re: Threads verwalten
 
Man ruft .Execute nicht direkt auf!
Und wo wie/wo ist InfoRecord definiert?

David Martens 23. Nov 2009 16:41

Re: Threads verwalten
 
Delphi-Quellcode:
 
  PInfoRecord = ^TInfoRecord ;
  TInfoRecord = record
                   WatchThreadID : Cardinal;
                   Meldung : string;
                 end;

procedure TWatchThread.OnNotifyChanged(Sender: TObject);
var
  InfoRecord : PInfoRecord;
begin
  // auf den Event reagieren
  // Liste der Dateien durchgehen, Änderungen mit FileZip speichern
 
  // Also so ???
  New(FoundRecord);
  InfoRecord^.WatchThreadID := GUID;
  InfoRecord^.Meldung      := 'Hier kommt der Text für die Meldung rein';
 
  PostMessage(MainForm.Handle, MY_WM_USER, SUB_MESSAGE_NEW_SAVE, Integer(InfoRecord));
end;

procedure TMainForm.ThreadMessage( var Message : TMessage );
var
  InfoRecord : PInfoRecord;
  ID : Cardinal;
begin
  case Message.WParam of

    MY_WM_USER :
      begin
        InfoRecord := PInfoRecord(Message.LParam);
        ID := ThreadIDToIndex( InfoRecord^.WatchThreadID );
        Memo.Lines.Add(InfoRecord^.Meldung);
        Dispose(InfoRecord);
      end;

end;
Sohier dachte ich.


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:16 Uhr.
Seite 1 von 2  1 2      

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