![]() |
Delphi-Version: 5
Absturz der Anwendung nach beenden eines Threads
Hi,
ich habe ein Programm, welches zur Runtime einen, oder mehrere Threads erzeugt. In diesen Thread läuft ein TCP-Client (TWSocket) der eine Verbindung zu einem TCP-Server hält. Wenn nun der TCP-Server sich verabschiedet, schickt er noch ein "Disconnect" rüber, damit sich der Thread mit dem TCP-Client abarbeiten und beenden kann, was er m.E. auch tut. Allerdings habe ich folgendes Phänomen: Wenn sie so ein Thread beendet hat, und ich klicke das Formular der Anwendung an, dann bekomme ich eine Zugriffsverletzung bei 0x00000000: Lesen von Adresse 0x00000000, bzw. System exception (code 0xc000041d) at 0x7702bda1. Auch innerhalb der IDE. Wenn ich aber das Formular nicht anklicke, dann läuft das Programm weiter, erzeugt auch neue Thread, und verbindet sich auch per TCP mit dem Server. Das kann ich x-mal machen, solange ich nicht das Formular der Mainform anklicke. Woher könnte sowas kommen? Wie kann ich feststellen ob der Thread wirklich beendet ist? Ich weiß nicht wirklich wie ich zur Ursache des Problems komme. PS: Oben steht die falsche Delphi-Version. Ist XE4, hab ich zu spät gesehen |
AW: Absturz der Anwendung nach beenden eines Threads
.. aus der Adresse lässt sich schliessen, dass auf eine Object-Instanz zugegriffen wird
die a) noch nicht erstellt wurder oder b) bereits wieder freigegeben wurde. ![]() Grüße Klaus |
AW: Absturz der Anwendung nach beenden eines Threads
Zitat:
Zitat:
Das der Fehler nur auftritt, wenn das Formular den Fokus bekommt, denke ich dass es mit irgendwelchen Fenster-Messaging zusammen hängt. Allerdings ist mir der Zusammenhang zwischen den Fensterbotschaften und den Thread nicht klar. Sicher ist nur, dass ich irgendwo eine Fehler habe. Ich speichere mir die Threads in einer TObjectList. Entfernt sich das Object (der Thread) selber aus dieser Liste wenn er terminiert ist, oder muß ich das selbst machen. Könnte der Fehler vielleicht daher kommen? Zur Zeit verwende ich die TObjectList noch nicht, ist für später vorgesehen. |
AW: Absturz der Anwendung nach beenden eines Threads
.. für den privaten Gebrauch ist madExcept kostenfrei.
Wenn ein Thread in einer TObjectList verwaltet wird terminiert, wird er nicht aus der Objectliste entfernt. Woher soll die Objectliste denn wissen ob ein Eintrag nicht mehr valide ist? Grüße Klaus |
AW: Absturz der Anwendung nach beenden eines Threads
Ich frag jetzt mal ganz blöd:
Wie finde ich den in der TObjectList am sichersten wieder (bzw. er sich selbst) und an welcher Stelle entferne ich ihn aus dieser am besten. Am Ende von der Execute-Methode? Ansonsten müßte ich ihn noch einen Indikator mit auf den Weg geben z.B. ein Handle, worüber ich ihn wiederfinden kann. |
AW: Absturz der Anwendung nach beenden eines Threads
Zitat:
Für den privaten Gebrauch ist es, wie schon gesagt wurde, kostenlos. |
AW: Absturz der Anwendung nach beenden eines Threads
Zitat:
Dann kannst Du durch die Objectliste gehen un die Threads auf finished abfragen. Dann musst Du den Thread freigeben und aus der Liste entfernen. Wenn bei der Objectlist ownsObject = true ist, dann reicht es den Thread aus der Liste zu löschen. Grüße Klaus |
AW: Absturz der Anwendung nach beenden eines Threads
Zitat:
Aber einen Timer dafür erscheint mir auch nicht unbedingt sinnvoll, zu mal der (zumindest in meinem Fall) dann x-mal die Liste durchsieht, und meistens halt nix macht. |
AW: Absturz der Anwendung nach beenden eines Threads
.. vielleicht kann das Ereignis onTerminate des Theads dazu verwendett werden
eine Message zu schicken. Grüße Klaus |
AW: Absturz der Anwendung nach beenden eines Threads
Zitat:
Zur Verwendung von TWSocket in Hintergrundthreads, die Property 'Multithreaded' und Hinweis auf ein Multihtreaded-Beispiel könnte das hier weiterhelfen: ![]() |
AW: Absturz der Anwendung nach beenden eines Threads
Zitat:
Grundsätzlich gehe ich aber mal davon aus, dass eher ich einen Fehler mache als Francois Piette :) |
AW: Absturz der Anwendung nach beenden eines Threads
Läßt sich das Problem anhand eines minimalen Beispielprojekts reproduzieren (das man dann hier posten könnte)?
madExcept würde ich bei Abstürzen auch als allererstes benutzen um den Callstack zu erhalten. (es ist fast schon ein must-have Werkzeug). |
AW: Absturz der Anwendung nach beenden eines Threads
Also ich habe mir jetzt im Thread im OnTerminate per PostMessage eine Message an den Hauptthread schicken lassen.
Dann rufe ich folgende Procedure auf
Delphi-Quellcode:
Erzeugen tu ich es so:
Writelog('Message TCPComThreadEnded empfangen');
for I := ComThreadList.Count-1 downto 0 do begin if TTCPThread(ComThreadList[i]).Finished then begin Writelog('FreeAnNil TCPComThread'); TTCPThread(ComThreadList[i]).Free; Writelog('Thread aus TObjectList entfernen'); ComThreadList.Delete(i); //<- Hier tritt eine Exception auf, dass das Object nicht mehr da ist. end; end;
Delphi-Quellcode:
Muß ich es auf der ComThreadList nicht mehr löschen?
TCPThread:=TTCPThread.Create(False, '192.168.177.71', localport, ip, port, self.Handle);
ComThreadList.Add(TCPThread); Wenn ich bei ComThreadList.Delete(i) eine Haltepunkt setze, und alle im Einzelschritt durchgehe, dann lande ich in der Unit "System.Classes" in der Funktion "TThread.destroy". Das kommt aber wahrscheinlich durch den Aufruf von .Free (2 Zeilen drüber). Und ich lande hier:
Delphi-Quellcode:
destructor TThread.Destroy;
begin if (FThreadID <> 0) and not FFinished and not FExternalThread then begin Terminate; if FCreateSuspended or FSuspended then Resume; WaitFor; end; RemoveQueuedEvents(Self); {$IF Defined(MSWINDOWS)} if (FHandle <> 0) and not FExternalThread then CloseHandle(FHandle); //<- Hier habe ich eine Exception: // Im Project WSPRG.exe ist eine Exception der Klasse $C00000005 mit der // Meldung 'Zugriffsverletzung bei 0x00000000: Lesen von Adresse 0x00000000' aufgetreten {$ELSEIF Defined(POSIX)} // This final check is to ensure that even if the thread was never waited on // its resources will be freed. if (FThreadID <> 0) and not FExternalThread then pthread_detach(pthread_t(FThreadID)); {$IF Defined(MACOS)} pthread_mutex_destroy(FCreateSuspendedMutex); {$ELSEIF Defined(LINUX)} sem_destroy(FCreateSuspendedSem); {$ENDIF LINUX} {$ENDIF POSIX} inherited Destroy; FFatalException.Free; end; |
AW: Absturz der Anwendung nach beenden eines Threads
Zitat:
|
AW: Absturz der Anwendung nach beenden eines Threads
Okay, das funktioniert :-) Danke Uwe.
Allerdings besteht mein ursprüngliches Problem immer noch. Jetzt habe ich mir mal das MADExcept heruntergeladen und auch in den madexcept Settings aktiviert. Meine Exe wird auch größer, und jetzt sollte doch eigentlich bei einer Exception ein Fenster mit Debuginfo's kommen. Allerdings bekomme ich nach wie vor entweder die Fehlermeldung von Windows, oder er geht ins Debugging der IDE. Muß man noch was anderes machen, damit madexcept die Exception abfängt? |
AW: Absturz der Anwendung nach beenden eines Threads
Entweder du sagst der Objektliste die soll das löschen (OwnsObjects) und selber löschst du das nicht mehr,
wobei hier das Delete die TThread-Instance löscht. Aber wenn du das unbedingt selber löschen willst, dann darf entwedet die Liste das nicht automatisch löschen (kein OwnsObjects) oder du mußt den "ungültigen" Zeiger via TObjectList.Extract rausholen. |
AW: Absturz der Anwendung nach beenden eines Threads
Ich habe jetzt OwnObjects:=False und lösche das Object jetzt selber. Das Free hab ich rausgenommen und so funktioniert es jetzt auch.
Aber mein Ursprüngliches Problem ist noch da und das mit dem madexcept will auch nicht funktionieren (Wär ich heut bloß im Bett geblieben) |
AW: Absturz der Anwendung nach beenden eines Threads
Zitat:
Wenn Windows die Exception fängt, dann müsste man das mal genauer untersuchen, wo die Exception hochkommt. Hast du alle Checks (Range checking, Overflow checking) aktiviert? |
AW: Absturz der Anwendung nach beenden eines Threads
Liste der Anhänge anzeigen (Anzahl: 1)
Okay, das mit den madexcept läuft jetzt. Ich habe eine bugreport, aus dem ich selbst leider nicht so viel herauslesen kann. Ich häng den mal an Anhang dran, vielleicht kann jemand etwas daraus erkennen.
Wenn ich dann in der madException auf Continue Application klicke, läuft meine Anwendung scheinbar weiter, bis ich der Mainform mal wieder den Focux spendiere. |
AW: Absturz der Anwendung nach beenden eines Threads
Zitat:
Es gibt also nur noch das Delete in der Liste. Nja, dann hast du den Thread-Zeiger nun aus der Liste, aber die Thread-Instanz gammelt als Speicherleck immernoch im Programm rum. Einwas davon mußt du schon noch machen (nur Eines und nicht Mehreres). |
AW: Absturz der Anwendung nach beenden eines Threads
Sorry, Ownobjects ist natürlich auf True. Hatte mich vertippt.
|
AW: Absturz der Anwendung nach beenden eines Threads
Liste der Anhänge anzeigen (Anzahl: 2)
Guten Morgen,
neuer Tag, neues Glück. Da mein ursprünglicher Fehler immer noch existiert, steige ich an dieser Stelle noch mal ein. Wie bereits gesagt, wird eine Exception ausgelößt, wenn mein Thread mit dem TCP-Client (TWSocket von ICS) beendet wird bzw. beendet ist, und ich anschließen der Mainform den Focus geben, z.B. durch anklicken. Was dann im Detail passiert kann ich schwer sagen. Aber ich nehme mal an, dass Windows sicherlich eine Window-Message schickt, deren Verarbeitung dann, aus welchen Gründen auch immer, fehlschlägt. In meinem Programm fange ich im Grunde keinerlei Messages ab, bis auf eine einzige, die mein Thread an die Mainunit schickt wenn er sich beendet, aber die habe ich erst später hinzugefügt. Der Fehler war schon vorher da. Leider weiß ich mir nicht zu helfen. Wenn ich den Thread nicht erzeuge, und dem zur Folge auch nicht beende, tritt natürlich kein Problem auf. Zu der Exception springt mir die der Debugger der IDE an folgende Stelle:
Delphi-Quellcode:
Ich habe mal eine Screenshot von der IDE an dieser Stelle gemacht und angehängt. Vielleicht hat ja irgendjemand noch eine Idee, was ich machen könnte um dem Fehler auf die Spur zu kommen.
{ Standard window procedure }
function StdWndProc(Window: HWND; Message: UINT; WParam: WPARAM; LParam: WPARAM): LRESULT; stdcall; {$IF Defined(CPUX86)} { In ECX = Address of method pointer } { Out EAX = Result } asm XOR EAX,EAX PUSH EAX PUSH LParam PUSH WParam PUSH Message MOV EDX,ESP MOV EAX,[ECX].Longint[4] CALL [ECX].Pointer ADD ESP,12 //<- Genau hier hin. POP EAX end; Meinen Thread häng ich auch noch mal dran, möglicherweise liegt der Fehler ja da drin. |
AW: Absturz der Anwendung nach beenden eines Threads
Die Fehlerstelle ist hier eine Zeile vorher, denn leider zeigt der Debugger die Position der Rücksprungadresse an.
Der Fehler ist also in dem CALL aufgetreten, bzw. in der aufgerufenen Methode. Zitat:
In welchem Thread-Kontext liegt das denn? (würde zwar MainThread vermuten, aber kann nicht schaden mal nachzusehn -> Thread-Status) |
AW: Absturz der Anwendung nach beenden eines Threads
Liste der Anhänge anzeigen (Anzahl: 1)
Hier ist der Thread-Status.
Ich muß zugeben, dass mein Wissen für die Beurteilung ob das nun der MainThread ist, nicht ausreicht. Was ich aber sehe, dass er wohl auf eine Adresse zeigt $00000000, die wohl nicht der MainThread sein dürfte. Sondern wohl eher mein TCP-Thread, der ja nicht mehr existiert. Da stellt sich mir gleich mal die Frage, wer schickt eine Fensterbotschaft an meinen (nicht mehr existierenden) Thread? Und das erste was mir dazu einfällt wäre ICS TWSocket, welches mit einen unsichtbaren Fenster im Hintergrund arbeitet (hab ich gelesen). Das TWSocket ist aber mit Free entfernt...hm...ich dreh mich im Kreis und mir wird schwindelig :pale: Hier mal der Screenshot vom Thread-Status: |
AW: Absturz der Anwendung nach beenden eines Threads
Hallo Captnemo,
vielleicht gibt es einen Konflikt beim Empfangen von Messages? Wenn die Messagenummer für ICS nicht explizit auf einen Startwert gesetzt wird, benutzt ICS als erste Nummer
Delphi-Quellcode:
. Ich bin mir zwar nicht sicher, ob das zu einem Problem führen kann, aber den ICS-Messages einen Startwert zu geben, kann ja nicht schaden.
WM_USER + 1
Um den Startwert zu setzen, benutze die Variable
Delphi-Quellcode:
in der Unit
GWndHandlerMsgLow
Delphi-Quellcode:
, bevor du deine erste ICS-Komponente erzeugst.
OverbyteIcsWndControl
Grüße Thomas |
AW: Absturz der Anwendung nach beenden eines Threads
Danke Thomas, das werde ich berücksichtigen.
Aber ich glaube ich bin dem Fehler auf die Spur gekommen. Ich habe mal alle Objecte die ich im Create erzeuge auskommentiert, und dann läuft mein Thread, läßt sich beende und alle ist Okay. Dann habe ich die schrittweise wieder eingebaut, und siehe da, als einen Timer wieder aufgenommen habe, tritt der Fehler wieder aus. Ohne jetzt noch alle anderen Objecte zu testen (was ich aber noch mache) würde ich dann vielleicht hier den Fehler erst mal suchen. Also im Thread.Create erzeuge ich den timer:
Delphi-Quellcode:
und im meiner Execute sieht's so aus:
FUpdateTimer:=TTimer.Create(Nil);
Delphi-Quellcode:
Was ist denn daran falsch? Ich erzeuge ihn....mach aber nix damit...und gebe ihn wieder frei. :gruebel:
procedure TTCPThread.Execute;
begin Try FUpdateTimer.Interval:=60000; Synchronize( Procedure begin frm_main.Writelog('Init TCP-Connection ('+FBindIP+'@'+IntToStr(FBindPort)+')>('+FHost+'@'+IntToStr(FPort)+')'); end ); //FTCPClient.Connect; while not Terminated do begin sleep(100); self.Terminate; if Terminated then begin // FUpdateTimer.Enabled:=False; break; end; end; finally Synchronize( Procedure begin frm_main.ReleasePort(FBindPort); end ); FUpdateTimer.Free; Synchronize( Procedure begin frm_main.Writelog('Thread beenden'); end ); end; end; |
AW: Absturz der Anwendung nach beenden eines Threads
:gruebel:
Nachdem ein Thread beendet wurde, wird dessen MessageQueue gelöscht (falls er Eine hat), kurz davor die verknüpften Windows (vermute ich mal) und man kann an ihn dann auch keine Message mehr senden. (eigentlich) Falls meine "Vermutung" nicht stimmt, dann würden die Windows ja in der Luft hängen, da ihre Messages immer nur im verknüpften Thread abgearbeitet werden. (Dem, wo das Control erstellt wurde) Die MessageQueue eines Threads wird beim ersten Zugriff generiert, erstes PostThreadMessage an den Thread, oder beim Erstellen eines Window in diesem Thread. [add] Zitat:
Damit gehört er zur nicht-threadsicheren VCL des Hauptthreads und gehört auch nur dort zerstört (Synchronize). Auch das Enabled gehört nicht in den Thread. Außer du erstellst den Timer im Thread und mußt deinem Thread natürlich auch eine Message-Verarbeitung spendieren, denn ohne werden die Messages des Timers dann nie verarbeitet. [add2] Zitat:
Delphi-Quellcode:
?
Exit;
|
AW: Absturz der Anwendung nach beenden eines Threads
Hab grad den Test umgekehrt gemacht. Nur TTimer weglassen, schon läuft mein Thread ohne Fehler und Probleme.
Nur was jetzt? TTimer im TThread...müßte doch gehen. |
AW: Absturz der Anwendung nach beenden eines Threads
Grad gefunden:
Zitat:
![]() :wall::wall: Gibt's nen Timer der Threadsafe ist? Ist der JvThreadTimer Theadsafe? Zitat:
![]() Versteh ich das richtig? |
AW: Absturz der Anwendung nach beenden eines Threads
TTimer verwendet die Funktion
![]() |
AW: Absturz der Anwendung nach beenden eines Threads
Zitat:
![]() Vorallem das Fette und Nachfolgendes. |
AW: Absturz der Anwendung nach beenden eines Threads
Zitat:
|
AW: Absturz der Anwendung nach beenden eines Threads
Zitat:
Hilfeauszug: Exit: Zitat:
Zitat:
Oder meintest du mein Terminate vor der Schleife? Das war nur zu Testzwecken drin, damit sich der Thread gleich wieder beendet, und ich somit testen konnte ob irgendeine andere Procedure für den Fehler verantwortlich war. |
AW: Absturz der Anwendung nach beenden eines Threads
Ja, das Break verlässt die Schleife und das Exit auch.
Im Grunde wollte ich nur sagen, daß die Execute-Methode bei allen 3. Varianten verlassen (Exit sagt das nur deutlicher, zum Programmierer) und der Thread beendet wird. :angel: Zitat:
Ob der TJvThreadTimer threadsave ist, weiß ich nicht, aber ich glaub das "Thread" im Namen sagt erstmal nur aus, wie er intern arbeitet. TTimer geht über SetTimer und wartet auf die WM_TIMER. Und der TJvThreadTimer erzeugt einen Thread, in dem er die Millisekunden wartet und dann das Ereignis manuell auslöst, ohne über die MessageQueue zu gehen. |
AW: Absturz der Anwendung nach beenden eines Threads
Zitat:
Ich schicke zeilenweise (TCP) mit Linemode=Enabled und Lineend=#13#10. Leider kommt aber beim Empfänger nicht immer die vollständige Zeile an. Zu 80% ist alles richtig und zwischendurch werden Zeichen "verschluckt", und zwar immer am Anfang der Zeile. Ist der Linemode hier grundsätzlich sicher? Bzw. auf der anderen Seite das OnDataAvailable? |
AW: Absturz der Anwendung nach beenden eines Threads
Zitat:
|
AW: Absturz der Anwendung nach beenden eines Threads
Zitat:
Ich habe jetzt den TJvThreadTimer an Stelle des TTimer verwendet und Schwupps....alles Prima. Ich arbeite noch nicht lange mit Threads, bzw. hatte früher nie die Notwendigkeit. Doch nun geht es nicht anders, und ich stelle langsam fest wie wichtig es ist Threadsafe zu arbeiten. Das Prinzip ist schon klar, doch bei der Umsetzung tappt man doch in so manche Falle ;) Dank des Forums und dank euch lern ich das auch noch :-D:-D |
AW: Absturz der Anwendung nach beenden eines Threads
Zitat:
Im TCP-Server im OnSessionAvailable die neue Session im Thread erzeugen und dort im OnDataAvailable alle ankommen in einen Messegebuffer vom Mainthread, und dort verarbeiten? |
AW: Absturz der Anwendung nach beenden eines Threads
Nein in einem eigenen Beitrag hier im Forum!
|
AW: Absturz der Anwendung nach beenden eines Threads
Zitat:
Ich sag mal so: Du hast eine Komponente erstellt und nur weil sie ein einem anderem Thread verwendet wird, ist sie damit nicht automatisch threadsave. :zwinker: Das kommt dann drauf an, wie die Steuerung arbeitet und ob sie eventuell entsprechend abgesichert ist, also vorallem dein Setzen des Intervalls oder des Enable. Das Free dagegen rufe man ja eh fast immer aus einem anderem Thread auf, womit es da weniger Probleme gibt. Aber vermutlich werden die das wohl bedacht haben. Und dann kommt es auch noch darauf an, ob die das Timer-Event synchronisieren. (wobei ich das jetzt nicht glaub, da der Timer dann ja ungenauer laufen würde) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:00 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 by Thomas Breitkreuz