Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi TThread und TTimer - Free führt zu Exceptions (https://www.delphipraxis.net/74919-tthread-und-ttimer-free-fuehrt-zu-exceptions.html)

DocE 10. Aug 2006 20:40


TThread und TTimer - Free führt zu Exceptions
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo zusammen!

Ich habe ein kleines Problem mit einem TThread.

In dem Thread erstelle ich dynamisch eine andere Komponente, die wiederum (u.a.) ein TTimer-Objekt enthält. Das stellt an für sich kein Problem dar. Gibt man jedoch die Komponente am Ende des Thread-Executes mit Free oder FreeAndNil frei, so kommt es zu folgenden Fehlermeldungen:

Mit Debugger:
Zitat:

Im Projekt TimerProject.exe ist eine Exception der Klasse EAccessViolation aufgetreten. Meldung: 'Zugriffsverletzung bei Adresse 00000000.
Lesen von Adresse 00000000'. Prozess wurde angehalten. Mit Einzelne Anweisung oder Start fortsetzen.
und

Zitat:

Im Projekt TimerProject.exe ist eine Exception der Klasse EOSError aufgetreten. Meldung: 'Systemfehler. Code: 1400.
Ungültiges Fensterhandle'. Prozess wurde angehalten. Mit Einzelne Anweisung oder Start fortsetzen.
Ohne Debugger:
Zitat:

Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000.
und
Zitat:

Die Anweisung in "0x00000000" verweist auf Speicher in "0x00000000". Der Vorgang
"read" konnte nicht auf dem Speicher durchgeführt werden.
Der letzte Fehler wiederholt sich so lange, bis man den Prozess beendet (Taskmanager).

Das passiert auch, wenn der Timer niemals Enabled wurde.

Führt man das Free bzw. FreeAndNil mit Synchronized aus, kommt es zu keinem Fehler. Aber warum? Bzw. warum kommt es ohne Synchronized zu einem Fehler und wie kann man das verhindern?

Ich habe lange getüftelt, bis ich herausgefunden habe, dass der Fehler überhaupt an dem Timer liegt. Jetzt weiß ich aber nicht mehr weiter. :(

Meine einzige Vermutung wäre evtl. noch, dass dem Timer evtl. ein gültiges Fensterhandle fehlt???

Um das Problem besser nachvollziehen zu können, habe ich ein kleines Programm geschrieben, das auf das nötigste beschränkt ist. Der Quelltext ist hier angehängt.

Ich bedanke mich schonmal für eure Hilfe!


Grüsse
...Doc

jensw_2000 10. Aug 2006 21:14

Re: TThread und TTimer - Free führt zu Exceptions
 
Warum nimmst du nicht den Destructor zum Freigeben von "MeineTimerKomponente".
Dann läuft es auch fehlerfrei ...


Delphi-Quellcode:
procedure TMyThread.MyFree;
begin
  //  FreeAndNil(MeineTimerKomponente);
end;

destructor TMyThread.Destroy;
begin
  FreeAndNil(MeineTimerKomponente);
  inherited destroy;
end;

DocE 10. Aug 2006 21:47

Re: TThread und TTimer - Free führt zu Exceptions
 
Hallo jensw_2000,

das funktioniert leider nur solange, wie Du den destructor falsch deklarierst. Ich gehe davon aus, dass Du diesen mit

Delphi-Quellcode:
destructor Destroy;
eingebaut hast und nicht mit

Delphi-Quellcode:
destructor Destroy; override;
In oberem Fall, wird dieser gar nicht beachtet, weshalb es scheinbar funktioniert. Das Objekt wird allerdings nicht freigegeben und belegt somit weiteren Speicher. Das macht zwar bei diesem kleinen Testprogramm nichts, im "echten" Programm ist das ganze doch um einiges speicherintensiver. Das Nicht-Freigeben stellt daher keine praktikable Lösung dar.

Mit unterer Implementierung kommt es leider zu den gleichen Fehlern, wie Anfangs erwähnt.

Das war also noch nicht des Rätsels Lösung...

Weiß noch jemand Rat?


Grüsse
...Doc

jensw_2000 10. Aug 2006 22:18

Re: TThread und TTimer - Free führt zu Exceptions
 
Zitat:

das funktioniert leider nur solange, wie Du den destructor falsch deklarierst
Stimmt leider. Sorry

TBx 10. Aug 2006 22:32

Re: TThread und TTimer - Free führt zu Exceptions
 
Hallo Doc!

Zitat:

Zitat von DocE
Meine einzige Vermutung wäre evtl. noch, dass dem Timer evtl. ein gültiges Fensterhandle fehlt???

Nein das ist definitiv nicht das Problem.
In TTimer wir ein nicht sichtbares Fenster erstellt. Über dieses wird dann mit dem eigentlichen Timer, der aus Windows selbst kommt, komuniziert (mal vereinfacht gesprochen):

Somit spaltet TTimer einen eigenen Thread ab.

Und Aufrufe zwischen verschiedenen Threads müssen nun einmal synchronisiert werden.

Btw: In dem Destroy von TMeineKomponente kannst Du Dir das Zerstören des Timers imho schenken, da Du diesem Deine Komponente als Owner zugewiesen hast und das Free somit automatisch ausgeführt wird.
Im Destroy des TTimer wird auch vorher der Timer disabled.

Hoffe das bringt ein kleines bißchen Licht ins Dunkel (auch wenn andere das vielleicht ein bißchen besser erklären können)

Gruß

onlinekater

DocE 10. Aug 2006 23:08

Re: TThread und TTimer - Free führt zu Exceptions
 
Hallo onlinekater,

Zitat:

Zitat von onlinekater
Somit spaltet TTimer einen eigenen Thread ab.

Und Aufrufe zwischen verschiedenen Threads müssen nun einmal synchronisiert werden.

Heißt das, dass TMeineKomponente "synchronized" freigegeben werden muss, da TTimer ebenfalls einen Thread erzeugt?

Ich finde das ganze dennoch etwas unlogisch. Der Timer war nie Enabled, also aktiv... Wieso macht der plötzlich nach der Freigabe Probleme? Ein Free auf den Timer sollte doch eigentlich das ganze ordentlich beenden.

Soweit ich das überblicken kann, würde ich TTimer nicht als einen Thread beschreiben, sondern eher, als eine Komponente, die Windows-Botschaften ausliest und bei WM_TIMER das Ereignis auslöst. Das Auslesen von Windows-Botschaften passiert, meiner Meinung nach, nur im idle Zustand, also wenn nichts anderes läuft bzw. Application.ProcessMessages aufgerufen wird. Sehe daher keinen Synchronisationszwang. Es ist für mich einfach unverständlich warum der Timer nachdem er freigegeben wurde, weiter Timer-Ereignisse auslösen will, dies jedoch zu einem Fehler führt...

Zitat:

Zitat von onlinekater
Btw: In dem Destroy von TMeineKomponente kannst Du Dir das Zerstören des Timers imho schenken, da Du diesem Deine Komponente als Owner zugewiesen hast und das Free somit automatisch ausgeführt wird.

Das Freigeben des Timers hatte ich vorher nicht im Destroy. War nur ein Versuch die Exceptions zu beheben -> brachte jedoch keinen Unterschied.

Noch eine Anmerkung zu den Fehlermeldungen: Diese kommen jeweils im TTimer eingestellten Intervall nach Freigabe der übergeordneten Komponente. Es scheint so, als lebe der Timer weiter, jedoch ohne eigentlich zu existieren.


Grüsse
...Doc

Muetze1 11. Aug 2006 07:16

Re: TThread und TTimer - Free führt zu Exceptions
 
Vielleicht hast du dem VCL Thread vor dem freigeben deines Threads noch nicht genügend Zeit gelassen die aufgelaufenen WM_TIMER Botschaften aus seiner Warteschlange abzuarbeiten, weshalb nach dem freigeben durch dein Thread weitere Ereignisse auflaufen?

DocE 11. Aug 2006 09:12

Re: TThread und TTimer - Free führt zu Exceptions
 
Hallo Muetze,

Zitat:

Zitat von Muetze1
Vielleicht hast du dem VCL Thread vor dem freigeben deines Threads noch nicht genügend Zeit gelassen die aufgelaufenen WM_TIMER Botschaften aus seiner Warteschlange abzuarbeiten, weshalb nach dem freigeben durch dein Thread weitere Ereignisse auflaufen?

Eigentlich dürften überhaupt keine WM_TIMER Botschaften auflaufen...

Ich habe noch ein bißchen rumprobiert (einen "eigenen" TMyTimer geschrieben und anschließend auf den constructor, den destructor und eine leere WndProc reduziert) und herausgefunden, dass es an folgendem liegt:

Delphi-Quellcode:
destructor TMyAllocate.Destroy;
begin

  Classes.DeallocateHWnd(FWindowHandle);
  (...)
end;
Läßt man DeallocateHWnd weg, kommt es nicht mehr zu diesem Fehler, lediglich zu einem Speicherüberlauf nach vielen erstellten Threads, da das Window ja nicht mehr richtig freigegeben wird.

Weiß jemand, ob DeallocateHWnd einen Synchronized-Aufruf benötigt und evtl. warum?


Grüsse
...Doc

xaromz 11. Aug 2006 09:19

Re: TThread und TTimer - Free führt zu Exceptions
 
Hallo,

das Problem ist Folgendes:
Zitat:

Zitat von msdn
Remarks
A thread cannot use DestroyWindow to destroy a window created by a different thread.

TTimer ruft im Destruktor MSDN-Library durchsuchenDestroyWindow auf. Das Erzeugen des Timers geschieht aber im Hauptthread beim Erstellen des Thread-Objekts. Deshalb existiert weiterhin ein Fenster mit einer Nachrichtenbehandlungsmethode eines TTimer-Objekts, welches aber nicht mehr existiert. Folglich kracht es.

Die Lösung ist simpel: Einfach den Timer erst in Execute erzeugen.

Gruß
xaromz

DocE 11. Aug 2006 11:37

Re: TThread und TTimer - Free führt zu Exceptions
 
Hallo xaromz,

das scheint es zu sein.

Die Sache hat mich einfach nicht ruhen lassen, auch wenn der Fehler mit Synchronize behoben werden konnte. Jetzt ist auch klar warum. Durch Synchronize wird das ganze ja wieder im Hauptthread ausgeführt, somit ist Erzeuger und Freigeber des Windows wieder derselbe.

Vielen Dank!

Jetzt ist nur noch die Frage, was besser ist. Erzeugen und Freigeben der Objekte im Hauptthread (also im TThread.Create bzw. mit Synchronize) oder besser beides im Thread selbst (also im Execute).

Ich sehe da evtl. noch die Gefahr, dass es zu Problemen kommt, wenn der Thread "abstürzt". Oder ist das unbegründet?


Grüsse
...Doc


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