[boost] Thread-Klasse



  • Hi, vor einigen Jahren habe ich C++ in der Berufsschule kennengelernt
    (auch, wenn wir da mehr mit C-Konstrukten gearbeitet haben, aber was soll's).
    In den letzten 2 1/2 Jahren habe ich durch's Studium intensiv mit Java und
    privat viel mit Python gearbeitet. Inzwischen will ich mich wieder an C++
    "ranwagen" - bisher problemlos.

    Allerdings komme ich beim Thema Multithreading nicht weiter. Von Java kenne
    ich die Thread-Klasse und habe eine solche in C++ gesucht. Nach einer Weile
    Googeln bin ich nun beim boost-Framework hängengeblieben. Allerdings klappt
    es nicht so recht, eine Thread-Klasse - wie ich sie aus Java kenne -
    nachzubauen. Erstmal hier der Code meiner parallel.cpp:

    #include <iostream>
    #include <boost/thread.hpp>
    #include <boost/bind.hpp>
    
    using namespace std;
    
    // meine Thread-Klasse
    class Thread {
        private:
            boost::thread* thread;
        public:
            Thread() {
                // hier versuche ich die run-Methode als Thread zu starten
                this->thread = new boost::thread(boost::bind(&Thread::run, this));
            }
            ~Thread() {
                this->thread->join();
            }
            virtual void run() {}
    };
    
    // und das ist dann meine von Thread abgeleitete Klasse
    class MyThread: public Thread {
        public:
            virtual void run() {
                // ... mit irgendwelchen Anweisungen
                cout << "foobar" << endl;
            }
    };
    
    int main() {
        MyThread* mt = new MyThread();
        delete mt; // damit der thread irgendwann "gejoint" wird und das Programm beenden kann
        return 0;
    }
    

    Kompiliere ich (btw verwende ich unter Linux Ubuntu den g++ als Compiler)
    meinen Code, erhalte ich einen Haufen (aus meiner Sicht) undefinierbarer
    Fehlermeldungen:

    /tmp/ccyQmUsE.o: In function boost::detail::thread\_data\_base::thread\_data\_base()': parallel.cpp:(.text.\_ZN5boost6detail16thread\_data\_baseC2Ev[\_ZN5boost6detail16thread\_data\_baseC5Ev]+0x1a): undefined reference tovtable for boost::detail::thread_data_base'
    /tmp/ccyQmUsE.o: In function Thread::~Thread()': parallel.cpp:(.text.\_ZN6ThreadD2Ev[\_ZN6ThreadD5Ev]+0x19): undefined reference toboost::thread::join()'
    /tmp/ccyQmUsE.o: In function boost::thread::thread<boost::\_bi::bind\_t<void, boost::\_mfi::mf0<void, Thread>, boost::\_bi::list1<boost::\_bi::value<Thread*> > > >(boost::\_bi::bind\_t<void, boost::\_mfi::mf0<void, Thread>, boost::\_bi::list1<boost::\_bi::value<Thread*> > >, boost::disable\_if<boost::is\_convertible<boost::\_bi::bind\_t<void, boost::\_mfi::mf0<void, Thread>, boost::\_bi::list1<boost::\_bi::value<Thread*> > >&, boost::detail::thread\_move\_t<boost::\_bi::bind\_t<void, boost::\_mfi::mf0<void, Thread>, boost::\_bi::list1<boost::\_bi::value<Thread*> > > > >, boost::thread::dummy*>::type)': parallel.cpp:(.text.\_ZN5boost6threadC2INS\_3\_bi6bind\_tIvNS\_4\_mfi3mf0Iv6ThreadEENS2\_5list1INS2\_5valueIPS6\_EEEEEEEET\_NS\_10disable\_ifINS\_14is\_convertibleIRSE\_NS\_6detail13thread\_move\_tISE\_EEEEPNS0\_5dummyEE4typeE[\_ZN5boost6threadC5INS\_3\_bi6bind\_tIvNS\_4\_mfi3mf0Iv6ThreadEENS2\_5list1INS2\_5valueIPS6\_EEEEEEEET\_NS\_10disable\_ifINS\_14is\_convertibleIRSE\_NS\_6detail13thread\_move\_tISE\_EEEEPNS0\_5dummyEE4typeE]+0x31): undefined reference toboost::thread::start_thread()'
    /tmp/ccyQmUsE.o: In function boost::detail::thread\_data<boost::\_bi::bind\_t<void, boost::\_mfi::mf0<void, Thread>, boost::\_bi::list1<boost::\_bi::value<Thread*> > > >::~thread_data()': parallel.cpp:(.text.\_ZN5boost6detail11thread\_dataINS\_3\_bi6bind\_tIvNS\_4\_mfi3mf0Iv6ThreadEENS2\_5list1INS2\_5valueIPS6\_EEEEEEED2Ev[\_ZN5boost6detail11thread\_dataINS\_3\_bi6bind\_tIvNS\_4\_mfi3mf0Iv6ThreadEENS2\_5list1INS2\_5valueIPS6\_EEEEEEED5Ev]+0x16): undefined reference toboost::detail::thread_data_base::~thread_data_base()'
    /tmp/ccyQmUsE.o:(.rodata._ZTIN5boost6detail11thread_dataINS_3_bi6bind_tIvNS_4_mfi3mf0Iv6ThreadEENS2_5list1INS2_5valueIPS6_EEEEEEEE[typeinfo for boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf0<void, Thread>, boost::_bi::list1<boost::_bi::value<Thread*> > > >]+0x8): undefined reference to `typeinfo for boost::detail::thread_data_base'
    collect2: ld gab 1 als Ende-Status zurück

    Ich hoffe, dass jemand eine Idee hat, was ich falsch mache 😃

    LG Glocke


  • Mod

    Du musst noch die libboost_thread dazu linken. Und wenn du das gemacht hast, auch noch den Compilerschalter -pthread (sowohl beim Linken als auch beim Compilieren).

    Aber wenn du mit dem g++ unter Linux unterwegs bist, dann nimm doch gleich die Threads aus der C++11-Standardbibliothek. Die sind ziemlich genau das gleiche wie die Boost-Threads + Futures&Promises, aber ohne dass du eine Abhängigkeit von Boost hast.



  • Glocke schrieb:

    Allerdings klappt es nicht so recht, eine Thread-Klasse - wie ich sie aus Java kenne - nachzubauen.

    Warum solltest du das tun wollen?

    Das ist wie wenn du daher kommst und sagst "ich kenne Autos schon aus England. Jetzt nehme ich ein Auto aus Deutschland und versuche die englischen Autos nachzubauen. Ich hab schon ein Lenkrad auf die andere Seite montiert und das andere abgebaut. Aber so richtig tut das noch nicht..."

    C++ ist nicht Java. Versuch also auch nicht, in C++ irgendwas nachzubauen, was du aus Java kennst. Vor allem dann nicht, wenn es in C++ schon was fertiges gibt.



  • Ich hab jetzt mal das Example von http://en.cppreference.com/w/cpp/thread/thread/thread genommen

    #include <iostream>
    #include <utility>
    #include <thread>
    #include <chrono>
    #include <functional>
    #include <atomic>
    
    void f1(int n)
    {
        for(int i=0; i<5; ++i) {
            std::cout << "Thread " << n << " executing\n";
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
    
    void f2(int& n)
    {
        for(int i=0; i<5; ++i) {
            std::cout << "Thread 2 executing\n";
            ++n;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
    
    int main()
    {
        int n = 0;
        std::thread t1; // t1 is not a thread
        std::thread t2(f1, n+1); // pass by value
        std::thread t3(f2, std::ref(n)); // pass by reference
        std::thread t4(std::move(t3)); // t4 is now running f2(). t3 is no longer a thread
        t2.join();
        t4.join();
        std::cout << "Final value of n is " << n << '\n';
    }
    

    und es probiert mit g++ test.cpp -o test -std=c++0x compiliert. Beim Ausführen kommt

    terminate called after throwing an instance of 'std::system_error'
      what():  Operation not permitted
    Abgebrochen (Speicherabzug geschrieben)
    

    Was hab ich diesmal veregssen? 🤡

    @pumuckl: Es gibt schon so eine Klasse? Warum finde ich die nicht 😞



  • SeppJ schrieb:

    [...] Und wenn du das gemacht hast, auch noch den Compilerschalter -pthread (sowohl beim Linken als auch beim Compilieren).
    [...]



  • Kein Kommentar xDD Danke 😃


  • Mod

    Glocke schrieb:

    Ich hab jetzt mal das Example von http://en.cppreference.com/w/cpp/thread/thread/thread genommen
    [...]
    @pumuckl: Es gibt schon so eine Klasse? Warum finde ich die nicht 😞

    Dies ist alles sehr verwirrend...



  • Glocke schrieb:

    @pumuckl: Es gibt schon so eine Klasse? Warum finde ich die nicht 😞

    Jup, die nennt sich std::thread... warum du nicht findest, was du die ganze Zeit schon benutzt, versteh ich auch nicht 🙂



  • Mal abgesehen davon, dass die Java-Threads so ziemlich der groesste Design-Fail ueberhaupt sind. Pfui Teufel.



  • Kellerautomat schrieb:

    Mal abgesehen davon, dass die Java-Threads so ziemlich der groesste Design-Fail ueberhaupt sind. Pfui Teufel.

    Na wenn der mächtige Kellerautomat das sagt muss es ja wohl stimmen einself.



  • class Thread implements Runnable
    

    🙄



  • Und das ist jetzt schlimm weil ...?



  • Ein Thread ist nichts, das man ausfuehrt, sondern etwas, das man etwas ausfuehren laesst. Daher zu behaupten, ein Thread sei ein Runnable (= implements), ist voelliger Schwachsinn. Sollte daher eher so sein:

    class Thread
    {
            private Runnable runnable;
    
            // ...
    }
    

    Und dann haette Thread auch keine run()-Methode, die das Runnable im selben Thread ausfuehrt.



  • Und deswegen ist die ganze Java-Threads Implementierung ein einziger Design-Fail. Hätten wir das auch geklärt.



  • Das Interface ist ein Design-Fail. Jop. :p


Log in to reply