Selfdelete und dann Thread beenden



  • Sorry, verlesen.

    Wenn ich ExitThread(); vor delete this; aufrufe, wird das Selfdelete ja gar nicht mehr ausgeführt um in den Destructor kann ich ExitThread(); auch nicht schieben, weil das Objekt auch von außen an anderer Stelle gelöscht wird und sonst ein Thread beendet werden würde, der eigentlich noch weiter laufen würde.



  • So, ich habs hingekriegt. Ich hab das Handle beim Erzeugen des Objektes mitgegeben und hatte dann auch das Handle was ich haben wollte, nicht das aktuelle, im Destruktor zur Verfügung. Thx für den Denkanstoß 😉 .



  • Also folgendes ist problemlos möglich, und AFAIK auch ganz legales C++:

    void Foo::Bar()
    {
        DWORD exitCode = this->DetermineExitCode();
        delete this;
        ::ExitThread(exitCode);
    }
    

    Wichtig ist bloss dass du "this" nach dem "delete this" nichtmehr dereferenzierst, nicht explizit und auch nicht implizit. Da ExitThread aber "this" nicht braucht, ist das OK.
    Blöd ist nur dass ExitThread kein stack-unwinding macht, und das kann durchaus ein Problem darstellen je nachdem von wo aus "Bar" aufgerufen wird.

    Besser wäre es wohl den Thread irgendwie "kontrolliert" zu beenden, also z.B. irgendeine Exception zu werfen die per definitionem nirgends gefangen wird.



  • hustbaer schrieb:

    ...
    Wichtig ist bloss dass du "this" nach dem "delete this" nichtmehr dereferenzierst, nicht explizit und auch nicht implizit. Da ExitThread aber "this" nicht braucht, ist das OK....

    hustbaer schrieb:

    ...
    Blöd ist nur dass ExitThread kein stack-unwinding macht, ...

    Naja, wenn Zweiteres nicht wäre, wäre Ersteres vermutlich nicht mehr gegeben, oder ? 😉

    Ich stimme Dir zu: Ich denke, das sollte man anders/besser lösen (Da sich einen Klasse nicht selbst erzeugt, sollte sie sich auch nicht selbst vernichten)...

    Gruß,

    Simon2.



  • An manchen Stellen kann sich die Klassen nun mal nur selbst löschen, z.B. nach dem ungeplanten Schließens einer User-Verbindung. Da wird bei send() und recv() geprüft ob die Verbindung geschlossen wurde und wenn das der Fall war, wird die Instanz aus ner Sammel-Map entfernt und dann mit delete this; gelöscht. Ich könnt zwar auch nen neuen Thread erstellen, der dann die Klasse löscht, wär aber auch ein sinnloser Aufwand, wenns so genauso geht.

    Nur noch eine Frage: wenn ein Thread mit TerminateThread() beendet wird, werden dann die Variablen, die normal mit int a; oder so angelegt wurden, wieder freigegeben oder bleiben die im Speicher liegen?



  • TerminateThread() schießt den Thread SOFORT ab, ohne Aufräumarbeiten. Aber du hast auch die Möglichkeit, den Thread sanft von innen zu beenden (wenn die Thread-Funktion per return verlassen wird, räumt der Thread auf und beendet sich dann).



  • Ich weiß bloß nicht wie ich das machen soll: der Thread hängt in einer Endlosschleife und in dieser wartet er wiederrum mit recv() auf ankommende Daten.



  • Dann mach doch aus der Endlosschleife eine "ordentliche" Schleife while(socket_active(src))... (keine Ahnung, mit welcher Funktion du den Socket-Status kontrollieren kannst).



  • Auf die Idee bin ich auch schon gekommen, aber in der Schleife empfängt er nicht nur am Anfang Daten sondern prüft was angekommen ist, schickt ne Antwort und wartet wieder. Da müsst ich ja an jede Stelle, an der recv(); aufgerufen wird innerhalb des Threads ein if schreiben um zu prüfen ob die Verbindung geschlossen wurde.



  • Ein ähnliches Problem habe ich auch mit der Funktion recv() (aus der Winsock2-DLL).
    Diese läuft in meinem Projekt ebenso in einem eigenen Thread. Nun würde ich gerne den Thread sauber beenden (ohne ExitThread oder TerminateThread), wenn der Anwender die aktuelle Sitzung beendet (das Hauptprogramm ist weiter aktiv!).

    Da recv() aber blockt, wüßte ich gerne, wie man die Verbindung von außen kappt, so daß der Thread sich selbst normal beenden kann.

    P.S.
    Hallo "Dr. C++":
    Wenn die Verbindung von außen geschlossen wird, so gibt recv() 0 zurück bzw. einen der vordefinierten Stati (z.B. WSAECONNRESET, WSAECONNABORTED oder WSAESHUTDOWN).

    Edit: Ich sehe gerade, daß im MSDN-Beispiel ein Fehler ist (wo ich die Infos herhabe). Die Funktion WSAGetLastError() gibt einen der definierten Fehlerwerte zurück, wenn recv() SOCKET_ERROR (-1) zurückgibt.



  • Simon2 schrieb:

    hustbaer schrieb:

    ...
    Wichtig ist bloss dass du "this" nach dem "delete this" nichtmehr dereferenzierst, nicht explizit und auch nicht implizit. Da ExitThread aber "this" nicht braucht, ist das OK....

    hustbaer schrieb:

    ...
    Blöd ist nur dass ExitThread kein stack-unwinding macht, ...

    Naja, wenn Zweiteres nicht wäre, wäre Ersteres vermutlich nicht mehr gegeben, oder ? 😉

    Ich stimme Dir zu: Ich denke, das sollte man anders/besser lösen (Da sich einen Klasse nicht selbst erzeugt, sollte sie sich auch nicht selbst vernichten)...

    Gruß,

    Simon2.

    Fix sakrament, wieso werden mir hier ständig die Worte im Mund verdreht. Ich habe nichts dagegen wenn sich Objekte selbst löschen, so wie z.B. in COM ist das vollkommen OK. Ich habe nur was dagegen einen Thread abzuschiessen der noch Objekte rumliegen hat.

    BTW: Wenn ExitThread stack unwinding machen würde, dann bräuchte man das ganze "delete this" nicht, d.h. es wäre auch kein Problem.

    ----

    @Dr. C++ : kapsel doch die Socket Verbindung in eine Klasse, und bring' der bei Exceptions zu werden wenn ein Socket Call fehlschlägt. Damit fliegt automatisch aus send/recv eine Exception raus wenn die Verbindung getrennt wrude, und das Problem ist gegessen.

    Es ist auf jeden Fall eine ganz schlechte angewohnheit unsaubere Lösungen mit "ja aber" zu rechtfertigen, so wie in "ja, aber die saubere Lösung wäre ja so viel Arbeit".



  • hustbaer schrieb:

    @Dr. C++ : kapsel doch die Socket Verbindung in eine Klasse, und bring' der bei Exceptions zu werden wenn ein Socket Call fehlschlägt. Damit fliegt automatisch aus send/recv eine Exception raus wenn die Verbindung getrennt wrude, und das Problem ist gegessen.

    Die Socket-Verbindungen sind bereits in einer Klasse untergebracht. Und mit den Exceptions: müsste ich dann um den ganzen "eigentlichen" Code ein try schreiben und darunter nur ein catch, das den Thread mit einem einfachen return beendet?!



  • Dr. C++ schrieb:

    Und mit den Exceptions: müsste ich dann um den ganzen "eigentlichen" Code ein try schreiben und darunter nur ein catch, das den Thread mit einem einfachen return beendet?!

    Kurz: Ja.



  • hustbaer schrieb:

    ...
    Fix sakrament, wieso werden mir hier ständig die Worte im Mund verdreht....

    😮
    Sorry, dann hatte ich Dein Posting mißverstanden.
    Also: Die Abneigung von "selbstlöschenden Objekten" ist meine ganz private eigene Meinung und hat nix mit hustbaer zu tun.

    Sorry,

    Simon2.

    Nachtrag:

    hustbaer schrieb:

    ...
    BTW: Wenn ExitThread stack unwinding machen würde, dann bräuchte man das ganze "delete this" nicht, d.h. es wäre auch kein Problem.
    ...

    Hmmmm vielleicht habe ich es noch nicht richtig begriffen, aber "delete this" brauche ich doch nur für Heapobjekte, die durch stack unwinding nicht automatisch abgeräumt werden .... oder hattest Du dann Destruktoren einer kapselnden Klasse im Sinn ?



  • @Dr. C++:
    Und du musst natürlich zusehen dass der ganze Code dazwischen exception safe ist... 🙂


Anmelden zum Antworten