thread und Vererbung



  • Hallo,

    ich hab ein Problem mit folgendem Code und kann nicht wirklich nachvollziehen woher dieses kommt:

    #include <iostream>
    #include <thread>
    #include <string>
    
    template <typename T>
    struct foo
    {
    	std::thread thread;
    	virtual void do_something(T t) = 0;
    	void run(T t) { thread = std::thread(&foo::do_something, this, t); }
    };
    
    struct bar : foo<const char *>
    {
    	std::string s;
    
    	bar() : s("") {}
    
    	void do_something(const char *ptr) override
    	{
    		s = std::string(ptr); // ptr zeigt auf "test"
    		std::cout << s << '\n'; // s ist leer!
    	}
    };
    
    int main()
    {
    	bar b;
    	b.run("test");
    }
    

    Und zwar wird hier nichts ausgegeben - obwohl bar::do_something ordnungsgemäß aufgerufen wird. Wenn ich im Debug Mode dort durchgehe, wird mir auch angezeigt dass ptr auf den string "test" zeigt. Die Zuweisung auf bar::s scheint aber schief zu laufen, denn in Zeile 22 bleibt der string leer.

    Was läuft da schief? Hängt das eventuell mit der Vererbung zusammen oder ist da was ganz anderes im Argen?


  • Mod

    Dein Thread wird vermutlich gekillt, bevor er überhaupt zu irgendwas kommt, da du nirgendwo join()st. Das sollte aber eigentlich auch irgendeine fette Fehlermeldung zur Laufzeit zur Folge haben.



  • Also bei mir in Visual Studio 2013 ist die Ausgabe "test" und du hast vergessen den thread in run zu joinen.



  • Aber ich will den thread noch nicht joinen...

    Also wenn ich mir einen breakpoint unter b.run("test") setze dann müsste doch irgendwann mal die Ausgabe kommen, oder (auch ohne join)? Also ich verlasse die Main nicht sondern warte da an dem breakpoint aber nichts passiert. Der thread müsste also noch leben und wird ja auch ausgeführt - nur passiert nix.



  • Die ostreams haben allerdings einen internen Puffer, der erst nach XXX Zeichen, einer Eingabe im getieten Stream (für cout ist das cin) oder im Destruktor passiert.
    Du siehst nichts, weil das nur in diesen Puffer geschrieben wird und nicht auf die Ausgabe. Musst den flushen.



  • happystudent schrieb:

    Aber ich will den thread noch nicht joinen...

    Also wenn ich mir einen breakpoint unter b.run("test") setze dann müsste doch irgendwann mal die Ausgabe kommen, oder (auch ohne join)? Also ich verlasse die Main nicht sondern warte da an dem breakpoint aber nichts passiert. Der thread müsste also noch leben und wird ja auch ausgeführt - nur passiert nix.

    Also in VS2013 gibt der bei mir auch, wenn ich join herausnehme den Text aus und crashed dann eine Sekunde spaeter.


  • Mod

    happystudent schrieb:

    Aber ich will den thread noch nicht joinen...

    Was heißt hier "noch nicht". Du joinst nirgends. Aber irgendwo musst du joinen, sonst kann so ein Programm nicht korrekt funktionieren. Mach's doch einfach mal.



  • Ruvi schrieb:

    Also in VS2013 gibt der bei mir auch, wenn ich join herausnehme den Text aus und crashed dann eine Sekunde spaeter.

    Echt? Ich benutze auch VS2013 und bei mir wird nichts ausgegeben (Debug Mode). Was meinst du mit "crashed eine Sekunde spaeter" - eine Sekunde nachdem das Programm beendet wurde oder eine Sekunde während du noch an einem Breakpoint hängst?

    SeppJ schrieb:

    Was heißt hier "noch nicht". Du joinst nirgends. Aber irgendwo musst du joinen, sonst kann so ein Programm nicht korrekt funktionieren. Mach's doch einfach mal.

    Ja, mit join gehts, das schon. Aber ich verstehe halt nicht warum? Nach meinem Verständnis wird mit run der thread erstellt und gestartet - richtig?

    Dann müsste doch der thread auch ohne join fertig werden wenn man lange genug wartet, oder? Weil join blockiert doch nur den aktuellen thread bis der andere thread fertig ist, aber der muss doch auch von alleine fertig werden können? Ich meine, do_something wird ja aufgerufen, nur macht es halt nicht das was es soll.



  • happystudent schrieb:

    Dann müsste doch der thread auch ohne join fertig werden wenn man lange genug wartet, oder? Weil join blockiert doch nur den aktuellen thread bis der andere thread fertig ist, aber der muss doch auch von alleine fertig werden können? Ich meine, do_something wird ja aufgerufen, nur macht es halt nicht das was es soll.

    Ohne das join läuft der Hauptthread einfach durch ohne zu warten und wenn der ans ende der main kommt ist das Programm zu ende und alle anderen Threads werden gekillt. Da der Hauptthread nichts zu tun hat passiert das quasi sofort so das der andere thread nicht dazu kommt irgendetwas zu machen.



  • TNA schrieb:

    Ohne das join läuft der Hauptthread einfach durch ohne zu warten und wenn der ans ende der main kommt ist das Programm zu ende und alle anderen Threads werden gekillt. Da der Hauptthread nichts zu tun hat passiert das quasi sofort so das der andere thread nicht dazu kommt irgendetwas zu machen.

    Nein, das Programm geht nicht zu Ende. Wie gesagt, ich setze einen Breakpoint in die letzte Zeile und warte dort. Aber auch nach Minuten passiert nichts obwohl das Programm noch läuft, das ist die eigentliche Fragestellung.


  • Mod

    Es ist wohl davon auszugehen, dass du deinen Debugger nicht korrekt benutzt. Multithreadanwendungen zu debuggen ist nicht ganz einfach.



  • happystudent schrieb:

    TNA schrieb:

    Ohne das join läuft der Hauptthread einfach durch ohne zu warten und wenn der ans ende der main kommt ist das Programm zu ende und alle anderen Threads werden gekillt. Da der Hauptthread nichts zu tun hat passiert das quasi sofort so das der andere thread nicht dazu kommt irgendetwas zu machen.

    Nein, das Programm geht nicht zu Ende. Wie gesagt, ich setze einen Breakpoint in die letzte Zeile und warte dort. Aber auch nach Minuten passiert nichts obwohl das Programm noch läuft, das ist die eigentliche Fragestellung.

    Siehe meinen Beitrag. Es passiert schon etwas, du siehsts nur nicht.
    Edit: Oder das, was SeppJ sagt.



  • Nathan schrieb:

    Siehe meinen Beitrag. Es passiert schon etwas, du siehsts nur nicht.

    Hm, ich hab ein std::cout.flush(); an den Ende des Codes angefügt und den Breakpoint danach gesetzt. Das Ergebnis ist sehr komisch: manchmal wird der string angezeigt (und zwar sofort bei erreichen des Breakpoints), meistens aber nicht (und dann bringt auch warten nichts)...

    SeppJ schrieb:

    Es ist wohl davon auszugehen, dass du deinen Debugger nicht korrekt benutzt. Multithreadanwendungen zu debuggen ist nicht ganz einfach.

    Hm Ok... wie debuggt man denn Multithreadanwendungen dann richtig? Einfach breakpoint setzen geht da nicht mehr?


  • Mod

    happystudent schrieb:

    Hm, ich hab ein std::cout.flush(); an den Ende des Codes angefügt und den Breakpoint danach gesetzt. Das Ergebnis ist sehr komisch: manchmal wird der string angezeigt (und zwar sofort bei erreichen des Breakpoints), meistens aber nicht (und dann bringt auch warten nichts)...

    Da hast du dir ja auch eine super Race-condition gebastelt.

    Ich versteh es einfach nicht. Wir haben dir doch schon längst gesagt, warum dein Code nicht funktioniert. Aber du scheinst irgendwie komplett zu ignorieren, wozu join da ist.



  • SeppJ schrieb:

    Ich versteh es einfach nicht. Wir haben dir doch schon längst gesagt, warum dein Code nicht funktioniert.

    Ich dachte es liegt daran dass ich meinen Debugger nicht richtig benutze und nicht an dem Code? 😕

    SeppJ schrieb:

    Aber du scheinst irgendwie komplett zu ignorieren, wozu join da ist.

    Ich ignoriere ja nicht komplett wozu join da ist, sondern versuche das Verhalten des Codes nachzuvollziehen. In der Doku zu std::thread::join steht:
    *
    "This blocks the execution of the thread that calls this function until the function called on construction returns (if it hasn't yet)."*

    Also muss man durch simples abwarten doch auch die Ausgabe bekommen (und danach join aufrufen).


  • Mod

    happystudent schrieb:

    Also muss man durch simples abwarten doch auch die Ausgabe bekommen (und danach join aufrufen).

    Aber tut denn der andere Thread überhaupt noch irgendwas, wenn du einen Breakpunkt setzt?



  • SeppJ schrieb:

    Aber tut denn der andere Thread überhaupt noch irgendwas, wenn du einen Breakpunkt setzt?

    Eigentlich schon (er geht zumindest in die Funktion rein und man kann auch manuell durchsteppen)... Aber ich werd jetzt erstmal ein Tutorial für Multithreading Debugging suchen, da es ja tatsächlich daran zu liegen scheint (dachte erst dass irgendwas mit dem Code nicht stimmt).



  • Im Visual Studio ist es AFAIK so, wenn der Debugger an einen breakpoint anhält, so wird das ganze Programm (-> alle Threads) angehalten.



  • firefly schrieb:

    Im Visual Studio ist es AFAIK so, wenn der Debugger an einen breakpoint anhält, so wird das ganze Programm (-> alle Threads) angehalten.

    Exakt.

    Theoretisch sollte bei dem Problem hier doch auch ein warten des Hauptthreads helfen, oder?
    Sprich anderen Thread starten, den Hauptthread für paar Sekudnen arbeiten oder schlafen lassen und erst dann aus der main-Funktion rausspringen.



  • Stimmt, ihr habt recht. Dann kann ich natürlich an meinem Breakpoint warten bis ich schwarz werde 😃

    Gut zu wissen 👍


Anmelden zum Antworten