[solved] boost::thread - Memberfunktion



  • 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 test2
    

    Die 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ück
    

    MFG XBert



  • XBert schrieb:

    Leider funktioniert das oben gepostete Beispiel auch nicht!

    Ich kompiliere unter Ubuntu mit

    g++ test2.cpp -o test2
    

    Du 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. :p

    Ich versuche solche Reihenfolge-, Speicherbereich- Dinger immer zu vermeiden.



  • dooooomi schrieb:

    Damit sollte es gehen:

    g++ test2.cpp -o test2 -lboost_thread-mt
    

    Danke, damit funktioniert es

    MFG XBert


Anmelden zum Antworten