AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

Threads verwalten

Ein Thema von David Martens · begonnen am 21. Nov 2009 · letzter Beitrag vom 25. Nov 2009
Antwort Antwort
Seite 2 von 2     12
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#11

Re: Threads verwalten

  Alt 23. Nov 2009, 18:25
InfoRecord ist ok. (Um noch sicherer zu gehen, sollte man auf den Rückgabewert von PostMessage reagieren, sonst läuft man Gefahr, dass ein MemLeak entsteht)

Aber nicht Mainform.Handle verwenden. Lieber das Handle mit an den Thread übergeben und dort aus privates Feld speichern.
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
taaktaak

Registriert seit: 25. Okt 2007
Ort: Radbruch
1.990 Beiträge
 
Delphi 7 Professional
 
#12

Re: Threads verwalten

  Alt 23. Nov 2009, 18:55
Zwischenfrage:

Da PostMessage die Nachricht in die Warteschlage ablegt, kann der Rückgabewert doch nur den Erfolg der Nachrichten-Ablage verkünden - damit wird nicht ausgesagt, dass der Empfänger sie bereits erhalten hat - korrekt??
Ralph
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#13

Re: Threads verwalten

  Alt 23. Nov 2009, 19:01
Zitat von taaktaak:
Zwischenfrage:

Da PostMessage die Nachricht in die Warteschlage ablegt, kann der Rückgabewert doch nur den Erfolg der Nachrichten-Ablage verkünden - damit wird nicht ausgesagt, dass der Empfänger sie bereits erhalten hat - korrekt??
Richtig. Aber wenn aus irgendeinem Grund die Nachricht nicht in die Nachrichtenschlange gesetzt werden kann, wird false zurückgeliefert und man sollte den Speicher selber freigeben.
Wenn der Empfänger allerdings die Nachricht einfach nur wegschmeißt oder vor dem Dispose eine Exception auftritt (->> besser try finally verwenden), kann man bei dieser Art Kommunikation nichts machen.
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
David Martens

Registriert seit: 29. Sep 2003
205 Beiträge
 
Delphi XE Enterprise
 
#14

Re: Threads verwalten

  Alt 23. Nov 2009, 21:47
Soweit bin ich jetzt:

Delphi-Quellcode:
const
  WM_MY_USER = WM_USER + 101;

type
  PInfoRecord = ^TInfoRecord ;
  TInfoRecord = record
                   GUID : string;
                   Meldung : string;
                 end;

  TWatchThread = class(TThread)
  private
    fHandle : HWND;

    procedure fisFileNotifyDirectoryChanged(Sender: TObject);
  public
    OneBackup : TOneBackup;
    FileNotify : TfisFileNotification;
    FileZip : TJvZlibMultiple;

    procedure StartWatch;
  protected
    procedure DoTerminate; override;
  public
    constructor Create(aOwner : TComponent; Handle : HWND); virtual;
  end;

  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    Button3: TButton;

    procedure OnEvent( var Message : TMessage ); message WM_MY_USER;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    ObjectList : TObjectList;
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TWatchThread.DoTerminate;
begin
  inherited;

  FileNotify.Stop;
end;

procedure TWatchThread.fisFileNotifyDirectoryChanged(Sender: TObject);
var
  InfoRecord : PInfoRecord;
begin
  if not Terminated then
  begin
    New(InfoRecord);
    InfoRecord^.GUID := OneBackup.GUID;
    InfoRecord^.Meldung := OneBackup.Name + ' - ' + FormatDateTime('hh:nn:ss.zzz', now) + ' - ' +
                           'FileNotify.MessageNo';

    PostMessage(fHandle, WM_MY_USER, 1, Integer(InfoRecord));

    // hier müssen die Änderungen abgespeichert werden
    // funktioniert noch nicht
// FileZip.CompressDirectory(OneBackup.WatchFolder,
// OneBackup.IncludeSub,
// OneBackup.BackupFolder + '\' + OneBackup.GUID + '.zip');
  end;
end;

procedure TWatchThread.StartWatch;
begin
  FileNotify.Subtree := OneBackup.IncludeSub;
  FileNotify.Start;
end;

constructor TWatchThread.Create(aOwner : TComponent; Handle : HWND);
var
  NewGUID: TGUID;
begin
  inherited Create(true);
  freeOnTerminate := true;

  fHandle := Handle;

  OneBackup := TOneBackup.Create;

  FileNotify := TfisFileNotification.Create(aOwner);
  FileNotify.OnDirectoryChanged := fisFileNotifyDirectoryChanged;

  with OneBackup do
  begin
    CreateGUID(NewGUID);
    GUID := GUIDToString(NewGUID);

    Name := '';
    WatchFolder := 'C:\Test\Treadtest'; // nur mal zum Testen
    BackupFolder := 'C:\Test'; // nur mal zum Testen

    ...

    FileNotify.Directory := WatchFolder;
    FileNotify.NotificationType := [noFilename, noDirname, noSize, noLastWrite, noCreation];
  end;

  FileZip := TJvZlibMultiple.Create(aOwner);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  WatchThread : TWatchThread;
begin
  WatchThread := TWatchThread.Create(Self, Self.Handle);

  // hier die Daten übergeben
  WatchThread.OneBackup.Name := Edit1.Text;

  TWatchThread(ObjectList.Items[ObjectList.Add(WatchThread)]).Start;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  i : integer;
begin
  for i := 0 to ObjectList.Count - 1 do
  begin
    TWatchThread(ObjectList.Items[i]).Terminate;
  end;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  TWatchThread(ObjectList.Items[ObjectList.Count - 1]).StartWatch;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ObjectList := TObjectList.Create;
  ObjectList.OwnsObjects := false;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  ObjectList.Free;
end;

procedure TForm1.OnEvent(var Message : TMessage);
var
  InfoRecord : PInfoRecord;
  ID : string;
begin
  case Message.Msg of

    WM_MY_USER :
      begin
        try
          InfoRecord := PInfoRecord(Message.LParam);
          ID := InfoRecord^.GUID;
          Memo1.Lines.Add(InfoRecord^.Meldung);
        finally
          Dispose(InfoRecord);
        end;
      end;
  end;
end;
Das Ganze funktioniert schon ganz gut nur die Speicherung und das Logging muß jetzt noch rein.

Ich werde aber die Komponenten für FileNotify und FileZip nochmal austauschen.
Die Gründe:
- TfisFileNotification sagt mir nicht welche Dateien geändert wurden, mit SHChangeNotify geht das
- TJvZlibMultiple scheint mir zu unflexibel (bzw. kein kompatibles Zipformat), mit TAbZipKit geht es vielleicht besser

Ich muß mir auch noch eine Struktur überlegen wie ich die Änderungen speichere.

Jetzt erst einmal werde ich, bei geder Änderung, alle Dateien in eine neue Zip-Datei speichern. Das ist zwar nicht so schön, aber reicht für meine Zwecke. Ich will ja nur den Fortschritt meiner Diplomarbeit dokumentieren und sichern und das möglichst auf einem USB-Stick/HDD.

Ich benutze TeXnicCenter und MiKTeX 2.8 in einem Mojo-Pack (das geht erstaunlich gut), solange keine vernünftige Portable Version raus ist und werde die tex-Dateien mit dem kleinen Programm zusätzlich auf dem USB-Stick speichern und zu Hause auf den Rechner kopieren. Das sollte reichen.
  Mit Zitat antworten Zitat
uoeb7gp
(Gast)

n/a Beiträge
 
#15

Re: Threads verwalten

  Alt 24. Nov 2009, 00:23
Hallo David Martens.

Also folgendes.

>> New(InfoRecord);
Ist nur innerhalb des Threadkontext (Threadobjekt) gültig.
Es handelt sich um lokalen Speicher, dies funktioniert
bei deinem Source nur weil Du keinen Thread erzeugst,
Wo ist das Execute???

Für Globalen Memory musst Du zB. GlobalAlloc verwenden, dieser Memory kann dann auch vom MainThread der Applikation
ohne Probleme verwendet werden.


>> PostMessage(fHandle, WM_MY_USER, 1, Integer(InfoRecord));

Ist nur solange in einer multithreaded Umgebung Gültig, solange kein weiteres Event kommt.
ZB. Event wird vom OS getriggert, thread hat noch Rechenzeit übrig, und es kommt innerhalb dieser noch zu
einem zusätzlichen Event, dann überschreibst Du den vorhergehenden Record, da Du diesen Asynchron
mit PostMessage in die MQ gepostet hast.
Hier musst Du Send Message verwenden.


>> FileZip := TJvZlibMultiple.Create(aOwner);

Hier musst Du berücksichtigen, dass VCL-Komponenten, die Du im Mainthread erzeugst, nicht Threadsave sind!
Syncronize, bzw. Sperrobjekte verwenden!

>> ObjectList : TObjectList;

Delphi-Quellcode:
  
  for i := 0 to ObjectList.Count - 1 do
  begin
    TWatchThread(ObjectList.Items[i]).Terminate;
  end;
Hier hilft Terminate alleine nicht, da du blockieren auf ein Event wartest, hier musst du nach dem
Terminate, noch das FileNotify - Handle schließen, sonst terminiert der Thread nicht.

Sieh Dir am besten mal das Thread Demo das mit Delphi mitgeliefert wird an.

lg.
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#16

Re: Threads verwalten

  Alt 24. Nov 2009, 09:01
Zitat von uoeb7gp:
>> New(InfoRecord);
Ist nur innerhalb des Threadkontext (Threadobjekt) gültig.
Das stimmt nicht. Es funktioniert genauso. Das ist ja genau der Sinn bei Threads, sie haben denselben Speicher. Nur der Stack ist für jeden Thread separat.
Selbst in den Delphi-Sourcen wird gelegentlich dieser Weg gegangen.
Nichtsdestotrotz gibt es bessere Varianten, aber da kann man bei Threads ewig streiten.

Zitat von uoeb7gp:

>> PostMessage(fHandle, WM_MY_USER, 1, Integer(InfoRecord));

Ist nur solange in einer multithreaded Umgebung Gültig, solange kein weiteres Event kommt.
ZB. Event wird vom OS getriggert, thread hat noch Rechenzeit übrig, und es kommt innerhalb dieser noch zu
einem zusätzlichen Event, dann überschreibst Du den vorhergehenden Record, da Du diesen Asynchron
mit PostMessage in die MQ gepostet hast.
Stimmt auch nicht. Genau deswegen arbeitet er ja mit New und Dispose. Das nächste Event erstellt einen neuen Record. Der alte ist immernoch gültig.


Zitat von uoeb7gp:
[
>> FileZip := TJvZlibMultiple.Create(aOwner);

Hier musst Du berücksichtigen, dass VCL-Komponenten, die Du im Mainthread erzeugst, nicht Threadsave sind!
Syncronize, bzw. Sperrobjekte verwenden!
Ich kenne TJvZlibMultiple nicht, aber ist es wirklich ein visuelles Objekt? Sieht mir eher nicht so aus. Die Threadsicherheit sollte man überprüfen, ich würde aber erstmal davon ausgehen, dass es sich nur um Dateiarbeit handelt und da IMHO nie Probleme mit Threads auftauchen.


Zitat:
>> ObjectList : TObjectList;

Delphi-Quellcode:
  
  for i := 0 to ObjectList.Count - 1 do
  begin
    TWatchThread(ObjectList.Items[i]).Terminate;
  end;
Hier hilft Terminate alleine nicht, da du blockieren auf ein Event wartest, hier musst du nach dem
Terminate, noch das FileNotify - Handle schließen, sonst terminiert der Thread nicht.
Genau deswegen wird ja eben nichtSendMEssage verwendet. Postmessage arbeitet asynchron. Dadurch entsteht hier kein Problem. (in diesem speziellen Fall würde nichtmal eins mit SendMessage entstehen).


Wo ich ein Problem sehe, ist:
  • In Do Terminate wird Filexxx.Stop aufgerufen. Das muss evtl. synchronisiert werden (kenne das dahinter liegende Objekt nicht).
  • Es werden zuviele Klassen in TThread.Create erstellt. Hier muss man ausnahmsweise mal mehr in Execute packen (erstellen, und löschen). Kann ich aber im Detail nicht weiter beurteilen, da mir der restliche Code sowie die verwendeten Komponenten fehlen.
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
uoeb7gp
(Gast)

n/a Beiträge
 
#17

Re: Threads verwalten

  Alt 24. Nov 2009, 11:28
Hallo sirius, hast Recht, war da total auf dem Holzweg (oder sonst wo?)!!!

Bei der >> ObjectList : TObjectList;, hab ich aber nicht das SendMessage
sondern das FileNotyfy Event gemeint, dies Blockiert ja, wenn sich im
Filesystem nichts ändert. Dh. Thread ist Terminated, aber dieser kann sich nicht
beenden wenn das FileNotify-Handle nicht geschlossen wird.

@David Martens hab ein tolles Tutorial gefunden, hab mich draus auch mal schlau gemacht "g"!

http://www.michael-puff.de/Developer...mit_Delphi.pdf

lg.
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#18

Re: Threads verwalten

  Alt 24. Nov 2009, 11:39
Zitat von uoeb7gp:
Bei der >> ObjectList : TObjectList;, hab ich aber nicht das SendMessage
sondern das FileNotyfy Event gemeint, dies Blockiert ja, wenn sich im
Filesystem nichts ändert. Dh. Thread ist Terminated, aber dieser kann sich nicht
beenden wenn das FileNotify-Handle nicht geschlossen wird.
Ja, das stimmt, wenn man so einen blockierenden Befehl hat, muss man bei Terminate diesen auch lösen. Ich dachte das macht FileNotify.Stop? Bin mir aber nicht sicher. Das sollte man dann aber auch nicht in "DoTerminate" sondern IMHO in einer überschriebenen "Terminate"-Methode machen.
--> also irgendiwe muss die Blockierung gelöst werden.
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
David Martens

Registriert seit: 29. Sep 2003
205 Beiträge
 
Delphi XE Enterprise
 
#19

Re: Threads verwalten

  Alt 25. Nov 2009, 15:06
Danke erstmal für die tolle Unterstützung.

Ja, ich hab vergessen die Objekte freizugeben. Wo mach ich das am besten im DoTerminate oder destructor von TWatchThread?
Ich würde die in den destructor packen, weil ich sie ja auch im constructor erstelle.

Zu den beiden VCL-Komopnenten, die sind nicht visuell (auch die Alternativen).

@sirius:
1. Warum muß das Filexxx.Stop eventuell synchronisiert werden? Das sagt der Komponente nur das es aufhören soll Events auszulösen, wennn an dem beoachteten Ordner Änderungen vorgenommen werden. Das sollte nicht zeitkritisch sein.
2. Warum soll ich das Erstellen der Komponenten ins Execute packen? Beim Erstellen passiert ja noch nicht viel, erst beim Starten (Filexxx.Start und Starten des Zipvorganges) legen die los.

@uoeb7gp:
Zitat:
Bei der >> ObjectList : TObjectList;, hab ich aber nicht das SendMessage
sondern das FileNotyfy Event gemeint, dies Blockiert ja, wenn sich im
Filesystem nichts ändert. Dh. Thread ist Terminated, aber dieser kann sich nicht
beenden wenn das FileNotify-Handle nicht geschlossen wird.
Moment, der FileNotyfy Event blockiert doch nicht. Im Grunde ist das auch nichts anderes als auf eine Message zu warten; Da blockiert nichts. Wenn ich auf eine Eingabe/Button-Klick warte blockiert das ein Programm ja auch nicht.

Das fisFileNotifyDirectoryChanged soll ja nur die Meldung für das Log absetzen und den Backup-Vorgang starten. Später kommen dann noch weitere Funktionen hinzu (detaillierter Datei(namen)test und Meldungen für Backup-start und Backup-erfolgreich/abgebrochen)
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#20

Re: Threads verwalten

  Alt 25. Nov 2009, 15:23
Zitat von David Martens:
1. Warum muß das Filexxx.Stop eventuell synchronisiert werden? Das sagt der Komponente nur das es aufhören soll Events auszulösen, wennn an dem beoachteten Ordner Änderungen vorgenommen werden. Das sollte nicht zeitkritisch sein.
Nur ist gut. Die Frage ist wie? Ich weis es eben nicht. Vielleicht wird nur ein Flag gesetzt, dann dürfte es gut gehen.

Zitat:
2. Warum soll ich das Erstellen der Komponenten ins Execute packen? Beim Erstellen passiert ja noch nicht viel, erst beim Starten (Filexxx.Start und Starten des Zipvorganges) legen die los.
Du redest von Messages etc. Das setzt voraus, dass diese Komponenten ein (unsichtbares) Fenster haben. Und diese müssen auch immer in dem Thread erstellt werden, in welchen sie benutzt werden. Und der Thread startet erst nach dem Constructor.
Diese Könnte neben den Fenstern auch noch bei anderen Systemressourcen der Fall sein.
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 20:44 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