[solved] boost::thread - Memberfunktion
-
Hallo XBert,
versuch's mal damit:#include <boost/thread/thread.hpp> #include <boost/bind.hpp> class my_class { public: my_class() : m_thread( boost::bind(&my_class::my_thread,this) ) // warning: 'this' : used in base member initializer list {} ~my_class() // optional { m_thread.join(); } private: void my_thread() { for(;;){ //mach was } } // -- Member boost::thread m_thread; // muss letzter Member in 'my_class' sein! };:xmas2: Werner
-
Werner_logoff schrieb:
boost::thread m_thread; // muss letzter Member in 'my_class' sein!Warum muß das so sein?
-
dooooomi schrieb:
Werner_logoff schrieb:
boost::thread m_thread; // muss letzter Member in 'my_class' sein!Warum muß das so sein?
Das muss sein, weil boost::thread beim Start des Thread sofort die Memberfunktion this->my_thread() ausführt (mit "this" aus dem zweiten Parameter an m_thread in der Initialisierungsliste). Dadurch wird eine Memberfunktion von my_class ausgeführt, die evtl. Daten von my_class verwendet oder verändert, bevor der Konstruktorrumpf von my_class erreicht wird. Wäre m_thread nicht der letzte Member, würden diese Daten evtl. verwendet oder verändert, bevor sie initialisiert wurden.
-
LordJaxom schrieb:
Das muss sein, weil boost::thread beim Start des Thread sofort die Memberfunktion this->my_thread() ausführt (mit "this" aus dem zweiten Parameter an m_thread in der Initialisierungsliste). Dadurch wird eine Memberfunktion von my_class ausgeführt, die evtl. Daten von my_class verwendet oder verändert, bevor der Konstruktorrumpf von my_class erreicht wird. Wäre m_thread nicht der letzte Member, würden diese Daten evtl. verwendet oder verändert, bevor sie initialisiert wurden.
Ok, das ergibt Sinn. Allerdings dürfte das dann auch nur die halbe Wahrheit sein, schließlich ist es nicht immer möglich, alle Member per Initialisierungsliste zu initialisieren. Und sollte der Thread virtuelle Funktionen der Klasse benutzen, darf er sowieso erst nach dem Konstruktor gestartet werden...
-
dooooomi schrieb:
Ok, das ergibt Sinn. Allerdings dürfte das dann auch nur die halbe Wahrheit sein, schließlich ist es nicht immer möglich, alle Member per Initialisierungsliste zu initialisieren.
Sie sind aber wenigstens schon konstruiert und Operationen darauf damit (hoffentlich) definiert. Eine Operation auf einem nicht initialierten Objekt dürfte sehr schnell völlig unvorhersebares Verhalten hervorrufen.
Und sollte der Thread virtuelle Funktionen der Klasse benutzen, darf er sowieso erst nach dem Konstruktor gestartet werden...
Ich bin mir auch nicht sicher, ob der Ausdruck (*this).my_class::my_thread() nicht auch noch dann undefiniert ist, wenn der Thread losläuft, bevor der Konstruktorrumpf von my_class erreicht wurde.
-
Man kann hier auch einfach nen boost::scoped_ptrboost::thread verwenden, dann kann man den Thread ganz normal im "Rumpf" des ctors starten.
-
Leider funktioniert das oben gepostete Beispiel auch nicht!
Ich kompiliere unter Ubuntu mit
g++ test2.cpp -o test2Die Fehlermeldung ist folgende:
/tmp/ccVLzgEt.o: In function `boost::mutex::mutex()': test2.cpp:(.text._ZN5boost5mutexC1Ev[boost::mutex::mutex()]+0x45): undefined reference to `boost::thread_resource_error::thread_resource_error()' test2.cpp:(.text._ZN5boost5mutexC1Ev[boost::mutex::mutex()]+0x4d): undefined reference to `boost::thread_resource_error::~thread_resource_error()' test2.cpp:(.text._ZN5boost5mutexC1Ev[boost::mutex::mutex()]+0x55): undefined reference to `typeinfo for boost::thread_resource_error' /tmp/ccVLzgEt.o: In function `boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf0<void, my_class>, boost::_bi::list1<boost::_bi::value<my_class*> > > >::~thread_data()': test2.cpp:(.text._ZN5boost6detail11thread_dataINS_3_bi6bind_tIvNS_4_mfi3mf0Iv8my_classEENS2_5list1INS2_5valueIPS6_EEEEEEED0Ev[boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf0<void, my_class>, boost::_bi::list1<boost::_bi::value<my_class*> > > >::~thread_data()]+0x16): undefined reference to `boost::detail::thread_data_base::~thread_data_base()' /tmp/ccVLzgEt.o: In function `boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf0<void, my_class>, boost::_bi::list1<boost::_bi::value<my_class*> > > >::~thread_data()': test2.cpp:(.text._ZN5boost6detail11thread_dataINS_3_bi6bind_tIvNS_4_mfi3mf0Iv8my_classEENS2_5list1INS2_5valueIPS6_EEEEEEED1Ev[boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf0<void, my_class>, boost::_bi::list1<boost::_bi::value<my_class*> > > >::~thread_data()]+0x16): undefined reference to `boost::detail::thread_data_base::~thread_data_base()' /tmp/ccVLzgEt.o: In function `boost::condition_variable::condition_variable()': test2.cpp:(.text._ZN5boost18condition_variableC1Ev[boost::condition_variable::condition_variable()]+0x3a): undefined reference to `boost::thread_resource_error::thread_resource_error()' test2.cpp:(.text._ZN5boost18condition_variableC1Ev[boost::condition_variable::condition_variable()]+0x42): undefined reference to `boost::thread_resource_error::~thread_resource_error()' test2.cpp:(.text._ZN5boost18condition_variableC1Ev[boost::condition_variable::condition_variable()]+0x4a): undefined reference to `typeinfo for boost::thread_resource_error' /tmp/ccVLzgEt.o: In function `boost::detail::thread_data_base::thread_data_base()': test2.cpp:(.text._ZN5boost6detail16thread_data_baseC2Ev[boost::detail::thread_data_base::thread_data_base()]+0x1b): undefined reference to `vtable for boost::detail::thread_data_base' /tmp/ccVLzgEt.o: In function `boost::thread::thread<boost::_bi::bind_t<void, boost::_mfi::mf0<void, my_class>, boost::_bi::list1<boost::_bi::value<my_class*> > > >(boost::_bi::bind_t<void, boost::_mfi::mf0<void, my_class>, boost::_bi::list1<boost::_bi::value<my_class*> > >, boost::disable_if<boost::is_convertible<boost::_bi::bind_t<void, boost::_mfi::mf0<void, my_class>, boost::_bi::list1<boost::_bi::value<my_class*> > >&, boost::detail::thread_move_t<boost::_bi::bind_t<void, boost::_mfi::mf0<void, my_class>, boost::_bi::list1<boost::_bi::value<my_class*> > > > >, boost::thread::dummy*>::type)': test2.cpp:(.text._ZN5boost6threadC1INS_3_bi6bind_tIvNS_4_mfi3mf0Iv8my_classEENS2_5list1INS2_5valueIPS6_EEEEEEEET_NS_10disable_ifINS_14is_convertibleIRSE_NS_6detail13thread_move_tISE_EEEEPNS0_5dummyEE4typeE[boost::thread::thread<boost::_bi::bind_t<void, boost::_mfi::mf0<void, my_class>, boost::_bi::list1<boost::_bi::value<my_class*> > > >(boost::_bi::bind_t<void, boost::_mfi::mf0<void, my_class>, boost::_bi::list1<boost::_bi::value<my_class*> > >, boost::disable_if<boost::is_convertible<boost::_bi::bind_t<void, boost::_mfi::mf0<void, my_class>, boost::_bi::list1<boost::_bi::value<my_class*> > >&, boost::detail::thread_move_t<boost::_bi::bind_t<void, boost::_mfi::mf0<void, my_class>, boost::_bi::list1<boost::_bi::value<my_class*> > > > >, boost::thread::dummy*>::type)]+0x40): undefined reference to `boost::thread::start_thread()' /tmp/ccVLzgEt.o: In function `my_class::~my_class()': test2.cpp:(.text._ZN8my_classD1Ev[my_class::~my_class()]+0xf): undefined reference to `boost::thread::join()' test2.cpp:(.text._ZN8my_classD1Ev[my_class::~my_class()]+0x20): undefined reference to `boost::thread::~thread()' test2.cpp:(.text._ZN8my_classD1Ev[my_class::~my_class()]+0x40): undefined reference to `boost::thread::~thread()' /tmp/ccVLzgEt.o:(.rodata._ZTIN5boost6detail11thread_dataINS_3_bi6bind_tIvNS_4_mfi3mf0Iv8my_classEENS2_5list1INS2_5valueIPS6_EEEEEEEE[typeinfo for boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf0<void, my_class>, boost::_bi::list1<boost::_bi::value<my_class*> > > >]+0x8): undefined reference to `typeinfo for boost::detail::thread_data_base' collect2: ld gab 1 als Ende-Status zurückMFG XBert
-
XBert schrieb:
Leider funktioniert das oben gepostete Beispiel auch nicht!
Ich kompiliere unter Ubuntu mit
g++ test2.cpp -o test2Du mußt gegen die Library linken, da Boost.Thread im Gegensatz zu vielen anderen Boost Libraries nicht nur aus Header-Files besteht.
Damit sollte es gehen:
g++ test2.cpp -o test2 -lboost_thread-mt
-
Ich finde es aber auch sehr gewagt, Annahmen zu machen, wann ein Member initialisiert wird.
Meines achtens ist die Lösung auch nicht so optimal!Gruß
tHOMY :xmas2:
-
Thomy schrieb:
Ich finde es aber auch sehr gewagt, Annahmen zu machen, wann ein Member initialisiert wird.
Meines achtens ist die Lösung auch nicht so optimal!Naja, gewagt ist das eigentlich nicht, denn die Reihenfolge der Initialisierung ist schließlich im C++-Standard klar definiert. Member in der Reihenfolge, in der sie in der Klassendefinition stehen (nicht die Reihenfolge der Initialisierungsliste!), Basisklassen vorher, abgeleitete Klassen hinterher.
Man muß sich dessen nur bewußt sein, sollte man irgendwann mal die Member der Klasse komplett umkrempeln.
-
Okay, stimmt, im Standard steht es fest. Hätte ich nicht gedacht!

Es macht den Code nicht gerade verständlich! Und wenn man das so schreibt und andere die Klasse dann evtl. ändern,
hat man mit hoher Sicherheit ein Problem. Gerade in größeren Projekten kommt es bei solchen Dingen oft zu Problemen.
Deswegen finde ich das wieder gewagt. :pIch versuche solche Reihenfolge-, Speicherbereich- Dinger immer zu vermeiden.
-
dooooomi schrieb:
Damit sollte es gehen:
g++ test2.cpp -o test2 -lboost_thread-mtDanke, damit funktioniert es
MFG XBert