Delphi-PRAXiS

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.

Bummi 13. Okt 2011 14:22

AW: Threads mit Ereignissen
 
Hast Du mal dummymäßig dieselbe Datei in ein anderes Wegschmeißverzeichnis extrahiert und versucht auf dem ursprünglichen Verzeichnis weiterzuarbeiten?

Nersgatt 13. Okt 2011 14:32

AW: Threads mit Ereignissen
 
Du meinst sowas in der Art?

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.ExtrBaseDir := 'C:\temp';
    zip.Extract;
    while zip.Busy do
      application.ProcessMessages;

  finally
    zip.Free;
  end;

end;
So wird die Datei nach c:\temp entpackt, importiert wird jedoch aus dem urprünglichen Pfad (also nicht aus der gerade entpackten Datei).

Interessante Erkenntniss: es stürzt trotzdem ab! :cyclops:
Ich hatte ja vermutet, dass ZipMaster die entpackte Datei noch nicht ordentlich freigegeben hat. Aber das scheints nicht zu sein.
Wenn ich auch noch zip.Extract auskommentiere, dann läuft es wieder problemlos durch. Da scheint irgendwo in den Tiefen von ZipMaster irgendwas gehörig schief zu laufen. :(

WladiD 13. Okt 2011 16:57

AW: Threads mit Ereignissen
 
Kommentiere mal die Application.ProcessMessages aus:

Delphi-Quellcode:
//while zip.Busy do
// application.ProcessMessages;

mjustin 13. Okt 2011 17:33

AW: Threads mit Ereignissen
 
Zitat:

Zitat von Nersgatt (Beitrag 1130255)
Fällt jemandem etwas auf?

Delphi-Quellcode:
  zip := TZipMaster19.Create(nil);

Die Komponente wird dynamisch erzeugt, ohne Owner. Gibt es auch dann einen Fehler, wenn die Komponente auf dem Formular angelegt wird? (Hintergrund bzw. Unterschiede: dann wird beim Einlesen des Formulars auch die Loaded Prozedur aufgerufen, und der Owner ist zugewiesen).

FredlFesl 17. Okt 2011 06:36

AW: Threads mit Ereignissen
 
Wieso muss es eigentlich Zipmaster sein? Ich hab mir abgewöhnt, meine Zeit mit dem Analysieren von Fehlern in Komponenten von Drittanbietern zu verplempern.

Nersgatt 17. Okt 2011 07:22

AW: Threads mit Ereignissen
 
was würdest Du denn empfehlen? Die Dateien ungepackt auf den Webspace zu laden ist keine Option. Denn das Packen verringert die Größe der Dateien um den Faktor 10 und die Clients haben nicht immer DSL zur Verfügung. Da muss man teilweise mit einem Modem klarkommen (ja, diese alte Crrrrr-Ring-deng-deng-ping-Dinger).

Medium 17. Okt 2011 08:35

AW: Threads mit Ereignissen
 
7zip (unten, als "Pascal LZMA SDK" - ist nen direkter Port von 7z auf Delphi/FP)

Mavarik 17. Okt 2011 12:22

AW: Threads mit Ereignissen
 
Hast Du mal den Virenscanner aus geschaltet?

Lass mich mal raten:

Glaskugelmode := true;

Roter Regenschirm?

Glaskugelmode := false;

Grüsse Mavarik

Nersgatt 17. Okt 2011 13:26

AW: Threads mit Ereignissen
 
@Frank: Ich hab zwar Urlaub, aber da konnte ich mich nicht zurückhalten, das mal eben auszuprobieren. Deine Glaskugel hat Recht mit dem roten Regenschirm. Und in der Tat: Virenscanner ausschalten - funktioniert. :roll:
Tja, was soll man machen? Den Kunden sagen, sie sollen nicht den roten Regenschirm verwenden? :?

Aber auf jeden Fall vielen Dank für die Hilfe! :dp:

Mavarik 17. Okt 2011 16:58

AW: Threads mit Ereignissen
 
Zitat:

Zitat von Nersgatt (Beitrag 1130845)
@Frank: Ich hab zwar Urlaub, aber da konnte ich mich nicht zurückhalten, das mal eben auszuprobieren. Deine Glaskugel hat Recht mit dem roten Regenschirm. Und in der Tat: Virenscanner ausschalten - funktioniert. :roll:
Tja, was soll man machen? Den Kunden sagen, sie sollen nicht den roten Regenschirm verwenden? :?

Aber auf jeden Fall vielen Dank für die Hilfe! :dp:

LOL... Auszug aus meinen AGB's

Zitat:

Wenn Sie auf Ihrem Computer Avira-Antivir verwenden, können wir keine einwandfreie Funktion unserer Software garantieren.
Der Einsatz unserer Software ist daher auf System mit Avira-Antivir untersagt. Für diese Systeme wird von uns kein Support geleistet.
Ein abschalten des Viren-Scanners ist nicht ausreichend. Nach der Deinstallation müssen Sie den RegCleaner von Avira zwingend verwenden!

KEIN Witz! Sondern bitterer Ernst. Bei 2500 Kunden und über vielen Jahr bewiesen!

Mavarik :coder:

mquadrat 17. Okt 2011 17:35

AW: Threads mit Ereignissen
 
Was ist denn die Ursache? Also was macht Avira denn anders als die anderen AV-Lösungen?

Mavarik 17. Okt 2011 18:03

AW: Threads mit Ereignissen
 
Zitat:

Zitat von mquadrat (Beitrag 1130894)
Was ist denn die Ursache? Also was macht Avira denn anders als die anderen AV-Lösungen?

Das genau ist die 10.000 EUR Frage...

Kann ich seit über 10 Jahre nicht beantworten...


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:24 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