Zeiger auf Thread-Instanz & Thread beenden
-
Hallo und Guten Morgen,
In einem Projekt an dem ich mitarbeite wird ein Thread beim Programmstart erzeugt, der erstmal angehalten ist:
TSerThread *SerThread=new TSerThread(true);1. Ich habe da erstmal noch Verständnisprobleme:
* Die gepostete Code-Zeile definiert & initialisiert einen Zeiger, auf eine Instanz eines TSerThread-Objekt?
* Die Instanz des TSerThread-Objekt wird gleichzeitig in dieser Zeile mit new erzeugt?
* Eine Instanz stelle ich mir immer als Kopie des Thread-Objekts vor?
* Das Ganze ist eine dynamische Speicherreservierung?Weiter im Text und zum eigentlichen Problem: Die Instanz des Thread-Objekts sollte ja mit delete wieder entfernt werden. Im Moment hat ein Kollege aber am Ende der Anwendung (also wenn man auf Beenden klickt) nur Folgendes geschrieben:
void __fastcall TForm3::Beenden1Click(TObject *Sender) { SerThread->Terminate(); Close(); } //---------------------------------------------------------------------------2. Reicht das aus, um die erste gepostete Codezeile zu bereinigen? Wenn ja, warum? Wenn nein, warum nicht?
Bitte helft mir beim Verstehen!Gruß und Danke für's Lesen
-
1. new reserviert Speicher, legt eine Instanz der angegebenen Klasse an und initialisiert diese mit dem benannten Konstruktor. Ein Zeiger auf die Instanz wird der Variable links vom Istgleich zugewiesen.
Der angegebene Konstruktor des Threads ist vermutlich identisch mit dem Konstruktor von TThread, also wird der Thread "suspended" erstellt.
Eine Instanz ist nicht unbedingt Kopie sondern erstmal ein eigenständiges Objekt auf der Grundlage der Klassendefinition. Man kann Objekte auch kopieren, dann sind sie in der Tat auch eigene Instanzen.
2. Kann reichen, wenn im Thread FreeOnTerminate=true ist. Dann räumt sich der Thread nach Beendigung selbst auf. Je nach Design kann das zu Problemen führen, wenn man nicht genau weiß, ob der Thread nun schon weg ist oder nicht. Deshalb empfehlen manche Leute, FreeOnTerminate=false zu setzen, nach dem Beenden mit Terminate auf das Tatsächliche Ende zu warten und dann das Thread-Objekt selbst zu löschen.
-
Super, vielen Dank soweit!

Morris Szyslak schrieb:
1. new reserviert Speicher, legt eine Instanz der angegebenen Klasse an und initialisiert diese mit dem benannten Konstruktor. Ein Zeiger auf die Instanz wird der Variable links vom Istgleich zugewiesen.
Ok, verstehe ich.
Morris Szyslak schrieb:
Der angegebene Konstruktor des Threads ist vermutlich identisch mit dem Konstruktor von TThread, also wird der Thread "suspended" erstellt.
Ja, genau:
__fastcall TSerThread::TSerThread(bool CreateSuspended) : TThread(CreateSuspended) { FreeOnTerminate = true; } //---------------------------------------------------------------------------Morris Szyslak schrieb:
Eine Instanz ist nicht unbedingt Kopie sondern erstmal ein eigenständiges Objekt auf der Grundlage der Klassendefinition. Man kann Objekte auch kopieren, dann sind sie in der Tat auch eigene Instanzen.
Der erste Satz ist klar, der Zweite verwirrt mich...
Morris Szyslak schrieb:
2. Kann reichen, wenn im Thread FreeOnTerminate=true ist. Dann räumt sich der Thread nach Beendigung selbst auf. Je nach Design kann das zu Problemen führen, wenn man nicht genau weiß, ob der Thread nun schon weg ist oder nicht. [...]
FreeOnTerminate ist true (siehe Konstruktor). Der Thread ist auch definitiv bis zum Schluss da, mal Suspended mal Resumed.
3. Hat das einen Einfluss auf das Vorgehen beim Thread-beenden, ob der Thread angehalten ist oder nicht?Morris Szyslak schrieb:
[...] Deshalb empfehlen manche Leute, FreeOnTerminate=false zu setzen, nach dem Beenden mit Terminate auf das Tatsächliche Ende zu warten und dann das Thread-Objekt selbst zu löschen.
4. Würdest du das auch empfehlen? Wenn ja, wie sieht "auf das tatsächlich Ende warten" aus und wie sieht "das Thread-Objekt selbst zu löschen" aus? Letzteres mit delete nehme ich an. Wie müsste dann die Syntax aussehen (passend zum Anfangs geposteten Anlegen der Instanz), so? :
delete TSerThread;oder so?:
delete &SerThread;Die Syntax von delete ist mir, bezogen auf meinen Fall, nicht ganz klar. In der Hilfe stehts so:
BCB3-Hilfe schrieb:
Operator delete
Syntax:
<::> delete cast_ausdruck
delete <array_name> [];In den VCL-FAQs habe ich keinen passenden Thread-Titel gefunden, wo ich des Rätsels Lösung IMHO hätte finden können. Bei Nutzung der Suchfunktion bekam ich zB das hier:http://www.c-plusplus.net/forum/viewtopic-var-t-is-165419-and-postdays-is-0-and-postorder-is-asc-and-highlight-is-%2Anew%2A+%2Adelete%2A-and-start-is-0.html (Wie kann ich denn einem Link einen eigenen Namen geben, damit er nicht so lang ist? [url="<eigener_name>"] ging nicht.)
Ist das relevant?Auch weiterhin Danke für's Lesen!
-
Hallo
Der erste Satz ist klar, der Zweite verwirrt mich...
Was verwirrt dich daran? Du kannst, wenn es die Klasse zuläßt, Kopien von bestehenden Instanzen erstellen.
Hat das einen Einfluss auf das Vorgehen beim Thread-beenden, ob der Thread angehalten ist oder nicht?
Normalerweise nicht. Das hängt aber auch davon ab was der Thread eigentlich macht.
Würdest du das auch empfehlen? Wenn ja, wie sieht "auf das tatsächlich Ende warten" aus
Stichwort ist die WinAPI-Funktion WaitForSingleObject. Eventuell ist auch eine manuelle Kontrolle möglich, siehe Observer-Pattern.
wie sieht "das Thread-Objekt selbst zu löschen" aus? Letzteres mit delete nehme ich an. Wie müsste dann die Syntax aussehen (passend zum Anfangs geposteten Anlegen der Instanz), so? :
delete erwartet immer Zeiger.
Und auch nicht den Klassennamen. Du must delete auf den Zeiger anwenden der auf den Thread zeigt.delete SerThread;bis bald
akari
-
*Edit* Mein Fehler. Editieren anstatt Zitieren gedrückt.
-
Ok, melde mich Montag wieder - schönes Wochenende und fröhlichen 3. Advent :xmas1:
-
Hallo
Wie gebe ich dem Link einen Namen, dann kann ich das noch editieren...???

delete SerThread;wirft eine EAccessViolation!!! Der Thread ist dabei Suspended!
Du must dir natürlich im Klaren sein was du wann löschen darfst.
- Ist die Thread-Instanz hinter dem Pointer überhaupt noch gültig, oder wurde sie schon vorher gelöscht? Insbesondere bei FreeOnTerminate == true ist sowas möglich
- Kann der Thread an dieser Stelle so einfach gelöscht werden? Die Interaktion mit Threads muß immer peinlich genau synchronisiert werden.
- Wird nach dem eigentlich erfolgreichem delete noch mal auf die Thread-Instanz oder Teile davon zugegriffen?Das ist aber alles nur mit genauer Kenntniss den Codes und des Zwecks zu beantworten. Las es lieber so wie es vorher war. Mir scheint du bist noch nicht der richtige um dich mit solchen Problemen zu beschäftigen.
bis bald
akari
-
Las es lieber so wie es vorher war. Mir scheint du bist nicht der richtige um dich mit solchen Problemen zu beschäftigen.
Upps.

Das sind klare Worte...
-
akari schrieb:
Das ist aber alles nur mit genauer Kenntniss den Codes und des Zwecks zu beantworten. Las es lieber so wie es vorher war. Mir scheint du bist noch nicht der richtige um dich mit solchen Problemen zu beschäftigen.
fixit schrieb:
Upps.

Das sind klare Worte...
Aber nicht verkehrt. Wenn das seine Meinung ist, dann find' ich es in diesem Fall gut wenn er sie sagt / postet! Er hat mehr Erfahrung als ich und hilft mir damit vielleicht auch weiter... Er hats ja nicht unhöflich oder herablassend gesagt.
akari schrieb:
Wie gebe ich dem Link einen Namen, dann kann ich das noch editieren...???

Den Link in meinem 2. Post meine ich natürlich. Weil ich dem keinen selbst gewählten Namen geben kann, ist der gesamte Thread leider unübersichtlich breit! Die Frage habe ich auch unter dem Link direkt schonmal gestellt, dort auch im passenden Zusammenhang, deswegen ist sie beim 2. Mal natürlich etwas kürzer ausgefallen. Also wie geht das denn nun: Einem Link einen eigenen Namen verpassen?
Ich möchte trotzdem erstmal noch versuchen das Problem zu lösen. Ich gehe mal mehr ins Detail:
Der Thread wartet auf den Empfang von Zeichen an der COM-Schnittstelle. Je nachdem, wo man sich gerade in der Anwendung befindet, ist der Thread im Resumed- oder Suspended-Zustand. Wenn man die Anwendung endgültig beendet, wird auch der Thread bereinigt und entfernt (bzw. sollte er). An jedem Punkt an dem man die Möglichkeit hat die Anwendung zu beenden, ist der Thread im Suspended-Zustand. Ich darf den Thread dann auch löschen, weil keine Kommunikation mehr stattfinden kann (COM-Schnittstelle geschlossen). Also JA, der Thread darf an dieser Stelle gelöscht werden. Inzwischen kenne ich den Code auch schon gut, das sollte also auch kein großes Hinderniss mehr sein.
Ich bin jetzt mal mit dem Debugger im BCB3 das Ende der Anwendung (wenn man das HauptForm schließt) jeweils für Fall 1 und Fall 2 durchgegangen:void __fastcall TForm3::Beenden1Click(TObject *Sender) { SerThread->Terminate(); // Fall 1 delete SerThread; // Fall 2 Close(); } //---------------------------------------------------------------------------1 Problem hatte ich dabei gefunden: dem Ereignis OnDestroy des HauptForm war die die Methode Beenden1Click zugeordnet. Die Methode wurde daher 2x durchlaufen. Der Zweite Aufruf von Fall 2 hat dann natürlich eine Exception verursacht. Jetzt lasse ich delete drinstehen, da man es ja bei vorherigen Nutzung von new so machen soll und es jetzt keine exception mehr wirft. Ich gehe davon aus, das der Thread somit sauber geschlossen und der Speicher freigegeben wird!? Weitere Probleme sehe ich erstmal nicht.