[boost.asio, boost.thread, C++0x.Lambdas] Reordering über Scope-Grenzen hinweg oder wie?
-
Ich versuch mich mal kurz zu fassen, ohne wichtige Details auszulassen

class ServerEvent; class Communicator { typedef std::function<void(ServerEvent const&)> Callback; Callback cb; Communicator(Callback const& c) : cb(c) {} void send(ServerEvent const& evt) const { cb(evt); } }; class Server { Communicator& comm; boost::asio::io_service ioService; std::unique_ptr<boost::asio::io_service::work> work; std::unique_ptr<boost::thread> serverThread; public: Server(Communicator const& c) : comm(c) , ioService() , work(new boost::asio::io_service::work(ioService)) , serverThread(new boost::thread([this](){ioService.run();}) {} ~Server() { work.reset(); //don't keep the service running serverThread->join(); } void sendClientEvent(ClientEvent const& evt) { ioService.post([this, evt](){processEvent(evt);}); } void processEvent(ClientEvent const& evt) { /* ... */ comm.send(/* some ServerEvent here */); /* ... */ } };Soviel zum Aufbau, der Server soll quasi ein Active Object sein, dem bei der Konstruktion ein Callback für die von ihm erzeugten Events übergeben wird und der die ClientEvents in seinem internen Thread asynchron verarbeitet.
(Wenns Anmerkungen/Verbesserungsvorschläge zum Design gibt bzgl. asio/threads, immer her damit!)
Nun zu meinem Problem:void some_test_function() { Communicator comm([&](ServerEvent const&) { foo(); }); { Server srv(comm); srv.sendClientEvent(/* some ClientEvent here */); } }Meinem naiven Verständnis zufolge, was der Compiler beim Code-Erzeugen verschieben darf und was nicht, würde ich annehmen, dass der Server auf jeden Fall vor dem Communicator zerstört wird. Ich habe jetzt aber im Debugger mehrfach access violations gehabt, weil im Serverthread auf den Communicator zugegriffen wurde, der garnicht mehr existierte. Wieso das?
-
Mal janz doof jefracht: was passiert wenn man in ner Lambda-Expression eine Referenz "by value" captured? Tut die dann zu "T" zerfallen, oder bleibt sie "T&"?
Falls zweiteres (was ich annehme, hab aber nicht nachgeguckt) hast du ein Problem in sendClientEvent() (bzw. später, wenn die gepostete Lambda-Expression aufgerufen werden tut).auto _=[](){}; //WTF?

-
Oder am besten gleich:
[](){[](){}();}();
-
hustbaer schrieb:
Mal janz doof jefracht: was passiert wenn man in ner Lambda-Expression eine Referenz "by value" captured? Tut die dann zu "T" zerfallen, oder bleibt sie "T&"?
Falls zweiteres (was ich annehme, hab aber nicht nachgeguckt) hast du ein Problem in sendClientEvent() (bzw. später, wenn die gepostete Lambda-Expression aufgerufen werden tut).Zweiteres, und ich habe das Problem nicht, weil ich in sendClientEvent evt explizit per value capture.
Es wird grade immer wilder: Ich habe den Communicator jetzt in einen shared_ptr gehängt und der Server hält ihn intern nicht per referenz, sondern einen weak_ptr. Beim weak_ptr.lock() sollte ich dann ja einen shared_ptr auf den communicator oder auf nichts bekommen - stattdessen gibts eine access-violation. Ich versuch das die Tage mal zu isolieren.
-
pumuckl schrieb:
hustbaer schrieb:
Mal janz doof jefracht: was passiert wenn man in ner Lambda-Expression eine Referenz "by value" captured? Tut die dann zu "T" zerfallen, oder bleibt sie "T&"?
Falls zweiteres (was ich annehme, hab aber nicht nachgeguckt) hast du ein Problem in sendClientEvent() (bzw. später, wenn die gepostete Lambda-Expression aufgerufen werden tut).Zweiteres, und ich habe das Problem nicht, weil ich in sendClientEvent evt explizit per value capture.
Nö, ersteres. Aber ja, genau deswegen ist das kein Problem.
Innerhalb der Lambda-Expression ist "evt" keine Referenz mehr sondern eine Kopie (Zumindest macht das MSVC so). Das meinte ich mit "zu T zerfallen".
-
Also mit deinem Beispielcode kann ich das Problem nicht nachvollziehen... läuft (nach Korrekturen von ein paar Tippfehlern) perfekt (MSVC 10, Debug & Release, x64, Windows 7).
ps: ideone.com kann ja leider entweder boost oder C++0x, aber leider nicht beides zusammen

-
hustbaer schrieb:
Nö, ersteres. Aber ja, genau deswegen ist das kein Problem.
Gnarf. Ja. Capture by value/reference ist analog zu call by value/reference, eben so, dass by value eine Kopie des Objektes anlegt, by reference eine Referenz darauf, ganz egal ob das, was "übergeben" wird, nun eine Referenz oder das Objekt selbst ist.
ZUm problem: Ich vermute, dass es irgendwelche Interferenzen mit dem turtle.mock Framework gegeben hat. Ich hatte dem Communicator einen MOCK_FUNCTOR übergeben, das ist ihm wohl irgendwie nicht bekommen. Ich versuche, da weiter ein Auge drauf zu haben. Trotzdem wäre es klasse, wenn die Multithreading-Gurus hier sich das grundsätzliche Design mal zu Gemüte führen können und mir sagen, wenn es da was zu verbessern gibt
