![]() |
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:
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.
procedure TImporter.EndImport;
begin if Assigned(FOnEndImport) then Synchronize( procedure begin FOnEndImport(); end); end; 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 |
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:
|
AW: Threads mit Ereignissen
Bei mir sieht das im Prinzip so aus:
Delphi-Quellcode:
Ich vermute den Fehler aber an anderer Stelle.
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; 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. |
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. :? |
AW: Threads mit Ereignissen
klingt nach einem Problem an das ich mich zu erinnern glaube, dass in meinem Fall ZipMaster noch etwas gesperrt hatte ....
|
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.
|
AW: Threads mit Ereignissen
Danke, hätte ich, ist nur schon ewig her dass ich das Teil verwenden musste ...
|
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; |
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.
|
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 04:07 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz