Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Threads mit Ereignissen (https://www.delphipraxis.net/163724-threads-mit-ereignissen.html)

Nersgatt 13. Okt 2011 11:23

Threads mit Ereignissen
 
Hallo,

ich habe ein Problem, dem ich nicht auf die Schliche komme. Ein Programm importiert eine große Menge Daten von einer Firebirddatenbank in eine andere Firebirddatenbank. Das wird in einem extra Thread erledigt. Der Mainthread stellt den Fortschritt dar (Progressbar, Statusmeldungen, Fehlermeldungen, etc).

Nun stürzt mir dieser Programmteil scheinbar zufällig an ganz verschiedenen Stellen mit der bekannten Meldung "Dieses Programm funktioniert nicht mehr..." ab. Wie komme ich dem auf die Schliche?

Ich hab so ein bisschen meine Kommunikation mit dem Mainthread in Verdacht. Die Threadklasse hat Ereignisse, auf die der Mainthread reagieren kann. So ein Ergeignis löse ich z.B. so aus:
Delphi-Quellcode:
procedure TImporter.EndImport;
begin
  if Assigned(FOnEndImport) then
    Synchronize(
      procedure
        begin
          FOnEndImport();
        end);
end;
Das heißt, ich rufe im Threadkontext (Threadklasse = TImporter) die Methode "EndImport" auf. So kann der Mainthread auf diese Ereignis reagieren. Das habe ich noch an weiteren Stellen, z.B. um eine Progressbar upzudaten.
Kann man das grundsätzlich so machen, oder gibts dabei Fallstricke, die ich nicht beachtet hab? Gibts bei den anonymen Methoden irgendwelche Gemeinheiten?

Danke!
Jens

Medium 13. Okt 2011 11:35

AW: Threads mit Ereignissen
 
Hm, ich wäre da mit Messages ran gegangen, so dass die Threads so weit wie möglich entkoppelt sind. Aber rein prinzipiell sehe ich auch bei deiner jetzigen Variante - zumindest so isoliert - keine ernsten Schnitzer. :gruebel:

Blup 13. Okt 2011 12:02

AW: Threads mit Ereignissen
 
Bei mir sieht das im Prinzip so aus:
Delphi-Quellcode:
procedure TImporter.EndImport;
begin
  {unnötiges Synchronize vermeiden}
  if Assigned(FOnEndImport) then
    Synchronize(DoOnEndImport);
end;

procedure TImporter.DoOnEndImport;
begin
  {wird im Hauptthread ausgeführt,
   FOnImport könnte inzwischen durch den Hauptthread geändert sein}
  if Assigned(FOnEndImport) then
    FOnEndImport();
end;
Ich vermute den Fehler aber an anderer Stelle.
Jeder Thread benötigt eigene Datenbankverbindung.
Auf keinen Fall dürfen datensensitive Steuerelemente mit dieser Datenbankverbindung arbeiten.
Innerhalb des Threads:
- Exceptions müssen auf jeden Fall abgefangen und verarbeitet werden
- In OnError-Events keine Meldungen oder ähnliches.
- Die Datenbankkomponenten dürfen keine Meldungen anzeigen, den Cursor verändern oder ähnliches.

Nersgatt 13. Okt 2011 12:14

AW: Threads mit Ereignissen
 
Der Zugriff auf die Datenbank läuft über DBExpress. Der Thread bekommt eine komplett eigene Connection zu DB, die nur er benutzt. Das selbe gilt für den ganzen anderen DB-Krams (TSQLQueries, etc). Die werden im Thread dynamisch erstellt und freigegeben. Exceptions werden auch abgefangen. Auf diese Punkte hab ich großen Wert gelegt.

Ich hab mal sämlich Kommunikation mit dem Mainthread auskommentiert. Daran scheint es nicht zu liegen. Ich ermittle in eine bisschen anderen Richtung, denn manchmal läuft der Import problemlos durch (immer mit den selben Daten).

Der Import ist eigentlich zweigeteilt. Die Quelldatenbank wird als Zip-Datei heruntergeladen und dann auf dem CLientrechner entpackt (läuft im Mainthread). Dann wird eine Verbindung zu der gerade entpacken DB aufgebaut und die Daten daraus importiert (Import dann im Thread). Es scheint so, als träte der Fehler nur auf, wenn man die DB wirklich direkt vorher runtergeladen hat. Macht man erst den Download, beendet das Programm, startet es wieder und startet dann den Import, läuft es Fehlerfrei durch...

ich liebe solche Fehler einen Tag vorm Urlaub. :?

Bummi 13. Okt 2011 12:20

AW: Threads mit Ereignissen
 
klingt nach einem Problem an das ich mich zu erinnern glaube, dass in meinem Fall ZipMaster noch etwas gesperrt hatte ....

CCRDude 13. Okt 2011 12:24

AW: Threads mit Ereignissen
 
Nenn es doch konkret... häufig wird bei Verwendung von TZipMaster nach Aufruf der Pack- oder Entpack-Methode nicht darauf gewartet, daß das Busy-Property wieder false wird.

Bummi 13. Okt 2011 12:26

AW: Threads mit Ereignissen
 
Danke, hätte ich, ist nur schon ewig her dass ich das Teil verwenden musste ...

Nersgatt 13. Okt 2011 12:42

AW: Threads mit Ereignissen
 
Hm, scheinbar lässt sich in der Tat das Problem auf das Entpacken reduzieren. Kommentier ich das aus, läuft es immer durch.

Die Abfrage auf das Busy-Flag fehlte in der Tat. Aber trotzdem scheint es da noch ein Problem zu geben. Fällt jemandem etwas auf?

Delphi-Quellcode:
procedure TfrmImportPSM.UnzipFile(AFilename: String);
var
  zip: TZipMaster19;
begin

  DeleteFileWhenExist(ChangeFileExt(AFilename, '.fdb'));

  zip := TZipMaster19.Create(nil);
  try
    zip.ZipFileName := AFilename;
    zip.ExtrBaseDir := ExtractFilePath(AFilename);
    zip.Extract;
    while zip.Busy do
      application.ProcessMessages;

  finally
    zip.Free;
  end;

end;

Luckie 13. Okt 2011 13:20

AW: Threads mit Ereignissen
 
Hat die Komponente kein Ereignis dafür? Wenn nicht und die Quellcodes zur Verfügung stehen, könnte es sich lohnen dieses selbst zu implementiere oder die Klasse entsprechend zu erweitern.

Nersgatt 13. Okt 2011 14:12

AW: Threads mit Ereignissen
 
Doch, es gibt ein OnStateChanged. Aber auch wenn ich hier auf die Beendigung warte, funktioniert es nicht. Es lässt sich definitiv auf das Entzippen reduzieren.
Hab nun auch die letzte Version von ZipMaster installiert, trotzdem keine Besserung. Dann hab ich mir dem ProcessMonitor mal verfolgt, was da geöffnet und geschlossen wird. So wie ich das sehe, wie die Datei nach dem entpacken ordentlich geschlossen.
Bin langsam mit meinem Latein am Ende, wo ich noch suchen könnte.


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:59 Uhr.
Seite 1 von 3  1 23      

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