TThread Problem (Zugriffsverletzung bei destroy)
-
Ich möchte von meinen Programmen prüfen lassen ob es eine neue Version gibt.
Wenn der Rechner jedoch keine Internetverbindung hat bzw. diese überlastet ist,
dauert es sehr lange bis ich einen Timeout bekomme. Ich würde daher die Abfrage gerne
in einem extra Thread laufen lassen um mein Programm nicht zu behindern.Leider taucht hier mein übliches Thread Problem auf. Ich bekomm eine Zugriffsverletzung
beim Beenden meines Programms, wenn ich das Programm sehr früh beende d.H. der Thread
noch läuft. Ich denke es hängt mit dem delete HTTP zusammen.Kann sich das bitte mal jemand anschauen?
#ifndef ClassCheckVersionH #define ClassCheckVersionH #define PROGVERSION 924 #include <vcl.h> #include <IdHTTP.hpp> #include <winsock.h> class cCheckVersion { private: public: TIdHTTP *HTTP; cCheckVersion(); ~cCheckVersion(); bool GetVersion(AnsiString sURL, int &iVersion); }; class cCheckVersionThread : public TThread { private: CheckVersion *CheckVersion; void __fastcall CheckForNewVersion(); protected: void __fastcall Execute(); public: __fastcall cCheckVersionThread(bool CreateSuspended); __fastcall ~cCheckVersionThread(); }; //--------------------------------------------------------------------------- #endif#pragma hdrstop #include "ClassCheckVersion.h" void __fastcall cCheckVersionThread::Execute() { MsgWaitForMultipleObjects(1,NULL,1, 1000, QS_TIMER); Application->ProcessMessages(); CheckForNewVersion(); } void __fastcall cCheckVersionThread::CheckForNewVersion() { int iVersion; if (CheckVersion->GetVersion("http://www.datei_mit_programm/version.php", iVersion)) { if (iVersion > PROGVERSION) { MessageDlg("Es ist eine neue Version verfügbar!", mtInformation, TMsgDlgButtons() << mbOK, 0); } } } __fastcall cCheckVersionThread::cCheckVersionThread(bool CreateSuspended): TThread(CreateSuspended) { CheckVersion = new cCheckVersion(); } __fastcall cCheckVersionThread::~cCheckVersionThread() { this->Terminate(); while (!this->Terminated) { MsgWaitForMultipleObjects(1,NULL,1, 50, QS_TIMER); Application->ProcessMessages(); } delete CheckVersion; } cCheckVersion::cCheckVersion() { HTTP = new TIdHTTP(NULL); } cCheckVersion::~cCheckVersion() { delete HTTP; } bool cCheckVersion::GetVersion(AnsiString sURL, int &iVersion) { Application->ProcessMessages(); bool bReturn; Application->ProcessMessages(); try { AnsiString sStatus = HTTP->Get(sURL); sStatus = sStatus.Trim(); Application->ProcessMessages(); iVersion = sStatus.ToIntDef(0); bReturn = true; } catch(...) { bReturn = false; } return bReturn; } //--------------------------------------------------------------------------- #pragma package(smart_init)
-
hat keiner eine Idee?
-
Du kannst VCL-Komponenten nicht einfach in die Luft (NULL) erstellen. Die brauchen Eltern... Ausserdem stellt sich mir die Frage: AUF WELCHER ZEILE ZUM HENKER ENTSTEHT DIE ZUGRIFFSVERLETZUNG?!?
Der Debugger hilft bei der beantwortung dieser Frage.
Ausserdem frage ich mich was diese Zeile soll?
delete CheckVersion;
-
Was kann man den bei einer VCL Komponente als Parent verwenden, wenn man sie dynamisch
erstellen lassen will? Wenn ich diese dynamisch in der Form erstellen lasse dann
nehm ich die Form das ist klar. Wenn ich die jedoch wie hier von einer Klasse erstellen
lasse was nehm ich dann? Muss ich die Form dann durchreichen oder gibt es eine andere
Möglichkeit? Ich hab das jetzt mal so geändert.die Klasse cCheckVersionThread legt ja mit
CheckVersion = new cCheckVersion();eine neue Instanz der Klasse cCheckVersion an. Ich dachte ich müsste diese mit
delete CheckVersion;am Ende wieder löschen. Ist dem nicht so?
wo die Zugriffsverletzung kommt weiß ich leider nicht sonst hätte ich das dazu
geschrieben. Es wird keine Zeile rot markiert.Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000
wenn ich das
delete CheckVersion;entferne kommt keine Zugriffsverletzung mehr, bleiben dann noch Reste meines Programms
im Speicher?
-
Hallo
Was kann man den bei einer VCL Komponente als Parent verwenden, wenn man sie dynamisch
erstellen lassen will? Wenn ich diese dynamisch in der Form erstellen lasse dann
nehm ich die Form das ist klar. Wenn ich die jedoch wie hier von einer Klasse erstellen
lasse was nehm ich dann? Muss ich die Form dann durchreichen oder gibt es eine andere
Möglichkeit?Parent != Owner.
Wenn du dir mal die Konstruktoren von VCL-Controls anschaust, haben die als Parameter Owner. Genauso einen brauchst du auch, diesen übergibst du einfach als Wert an den Konstruktor des abgeleiteten COntrols.Tip : Benutze den Dialog Komponente/Neue Komponente..., um die das Basiscontrol auszusuchen, von dem du ableiten willst.
Dann wird eine korrekte Klasse erstellt, die du nur noch ableiten brauchst.bis bald
akari
-
Vielen Dank! Ich hab das jetzt auf den Owner geändert.
Das mit dem delete ist mir aber immer noch nicht klar.
-
Acidmrp schrieb:
entferne kommt keine Zugriffsverletzung mehr, bleiben dann noch Reste meines Programms
im Speicher?Klar bleibt das... Aber eine KLasse kann sich ja nicht selber löschen (o; Bzw. das kann sie schon... nur eine kleine Frage an dich: Wann wird der Destruktor einer KLasse aufgerufen?
-
danke für die Antwort.
Ist klar das die Klasse sich nicht selber löschen kann. Das macht sie aber doch auch gar
nicht.Die Klasse cCheckVersionThread erstellt eine Instanz der Klasse cCheckVersion
wenn dann der Thread gelöscht wird soll dieser im Destruktor natürlich auch noch die
von ihm angelegte Instanz der Klasse cCheckVersion löschen.Die Form1 erstellt von der Klasse cCheckVersionThread eine Instanz, diese wird dann
in void __fastcall TForm1::FormDestroy(TObject *Sender) wieder gelöscht.Das Kernproblem liegt hier:
- die Hauptanwendung erzeugt und startet einen neuen Thread der eine zeitauwendige
Operation durchführt
- die Hauptanwendung wird beendet solange jedoch die Zeitaufwendige Operation vom
Thread noch läuft
- wenn nun der Thread gelöscht wird läuft er ja nochd.h. muss ich solange warten bis die Zeitaufwendige Operation vom Thread beendet ist?
Oder kann ich den Thread irgendwie zwingen sich selbst sofort zu beenden damit ich ihn
ohne Gefahr lsöchen kann?
-
Acidmrp schrieb:
d.h. muss ich solange warten bis die Zeitaufwendige Operation vom Thread beendet ist?
Ja. Oder eine Abort-Funktion aufrufen die die zeitaufwändige OPeration vorzeitig beendet.
Acidmrp schrieb:
Oder kann ich den Thread irgendwie zwingen sich selbst sofort zu beenden damit ich ihn ohne Gefahr lsöchen kann?
kein guter Ansatz.
-
kann man TIdHTTP irgendwie sagen, dass es abbrechen soll? Das Problem besteht
hauptsächlich dann wenn die entsprechende Seite nicht erreichbar ist. Dann dauert es
schon mal eine Minute bis Indy sich geschlagen gibt.
-
... was sagt denn die Indy-Doku dazu?
-
leider find ich nur bei Indy 9 einen Timeout zum Abbrechen find ich gar nichts
