threadFunktion und KlasseMemberFunktion Problem



  • Hallo, liebe C++-Gemeinde,

    so spät poste ich immernoch mein Problem, da ich nicht schlafen kann.

    Das Problem ist, wenn ich
    threadFunktion benutze, funktioniert t.getNr() nicht mehr, anderes Wort,
    wenn ich t.getNr() aufrufe, bekomme ich immer den Wert, mit dem im Konstruktur
    initialisiert wird (hier ist 0), und nicht den Wert, den ich erwarte.

    Ohne threadFunktion zu benutzen, funktioniert es dagegen richtig.

    Weiß jemand, wo das Problem liegt ?

    void *threadFunktion( void *arg ); 
    
    class Test 
    { 
    public: 
        Test(); 
        void readAndStoreData(); 
        int getNr();
    private: 
        int nu; 
    };
    
    #include <pthread.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <fcntl.h>
    #include <termios.h>
    #include <iostream.h>
    
    Test::Test()
    {
        nu = 0;
    }
    
    void Test::readAndStoreData()
    {
        for ( int i=0; i<10; i++ )
        {
           nu = i+2;
           cout << " nu = " << nu << endl;
           sleep(1);
        }
    }
    
    int Test::getNr()
    {
        return nu;
    }
    
    void *threadFunktion( void *arg ) 
    { 
        // do was 
        Test myt;
        myt.readAndStoreData();     
        return NULL; 
    }
    
    #include "test.h"
    #include <iostream.h>
    
    int main()
    {
        pthread_t mythread;
        Test t;
    
        if(pthread_create(&mythread,NULL,threadFunktion,NULL))
           abort();
    
        for ( int i=0; i<10; i++ )
        {
            cout << "t.getNr() = " << t.getNr() << endl;
            sleep(1);
        }
    
        if(pthread_join(&mythread,NULL))
           abort();
    
        return 0;
    }
    

    Wenn ich threadFunktion in der Klasse deklariere, wie kann ich den Methoden-Namen als Übergabeparameter pthread_create(&mythread,NULL,threadFunktion,NULL) übergeben ? Hat jemand irgend eine Idee ?

    Vielen Dank und gute Nacht !

    Compilieren:

    g++ main.cpp test.h test.cpp -o test -lpthread

    Aufruf:

    ./test



  • Die ThreadFunktion arbeitet ja auch mit einem ganz
    anderen Objekt. Da ist es ja klar das sich an t.get()
    nichts ändert.
    Eine Methode der Klasse an pthread kannst du nur übergeben
    wenn sie static ist. Weil die Methode ja sonst nicht
    wüsste auf welches Objekt sie sich bezieht.
    Wenn sie nu verändern soll muss das dann natürlich
    auch static sein.

    Kurz:
    Entweder du verwendest static Methoden und Member.
    Oder du übergibts der ThreadFunktion zusätzlich einen
    Zeiger auf ein Test-Objekt das es verändern soll.
    (4. Parameter von pthread_create wenn ichs noch richtig weis)



  • Danke für die Antwort.

    Du hast richt. Das problem ist schon erledigt.

    Die Lösung:

    Test t;
    void *threadFunktion( void *arg ) 
    { 
        // do was 
        t.readAndStoreData();     
        return NULL; 
    } 
    
    int main()
    {
        pthread_t mythread;
    
        if(pthread_create(&mythread,NULL,threadFunktion,NULL))
           abort();
    
        for ( int i=0; i<10; i++ )
        {
            cout << "t.getNr() = " << t.getNr() << endl;
            sleep(1);
        }
    
        if(pthread_join(&mythread,NULL))
           abort();
    
        return 0;
    }
    

    Deine Idee mit static Methoden und Member... werde ich später noch probieren, da ich momenten unter Zeitdruck bin. vielen vielen danke 👍 😋 😋



  • Ne globale Variable ist wohl die schlechteste
    Lösung, da sie nicht Thread-Sicher ist.
    Sobald dann nämlich mehrere Threads gleichzeitig auf
    das Test-Objekt zugreifen bekommst du ernsthafte Schwierigkeiten.

    Ziehe dann zumindest die Benutzung von Mutexen in Frage!



  • Storm.Xapek.de schrieb:

    ...da sie nicht Thread-Sicher ist....

    Was gerade in DIESEM Zusammenhang ja wohl ein starkes Argument ist. 😉

    @rena: Schau doch mal hier.

    Stichwort: cast.

    Gruß,

    Simon2.



  • Was haltet ihr davon?

    #include <iostream>
    #include "Process.h"
    #include "Windows.h"
    
    using namespace std;
    
    template<class ThreadType>
    void ThreadStartProc(void* arg)
    {
       ((ThreadType*)arg)->Run();
    }
    
    template<class ThreadType>
    class ThreadBase 
    {
    public:
       void Start()
       {
          threadHandle = _beginthread(ThreadStartProc<ThreadType>,0,this);
       }
    
       virtual void Run() = 0;
       /*
       ...Stop()
       ...Join()
       */
    private:
       uintptr_t threadHandle;
    };
    
    class MyThread : public ThreadBase<MyThread>
    {
       /*
       MyThread(.... meine initialisierung .... )
       */
    public:
       virtual void Run()
       {
          cout << "Run" << endl;
          //... meine arbeit
       }
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
       MyThread thread;
       thread.Start();
       ::Sleep(1000);
    }
    


  • Bei Threads in C++ ist boost.thread immer die erste Wahl. Das ist zum einen Plattform überggreifend und zum anderen relativ einfach anzuwenden. Der Code hier sähe mit boost.thread etwa so aus.

    #include <boost/bind.hpp>
    #include <boost/thread/thread.hpp>
    // ... class Test u.a. includes
    
    int main()
    {
        using namespace std;
        Test t;
        boost::thread thrd( boost::bind( &Test::readAndStoreData, &t ) );
        for( int i=0; i<10; ++i )
        {
            cout << "t.getNr() = " << t.getNr() << endl;
            sleep(1);
        }
        thrd.join();
        return 0;
    }
    

    eine eigene Thread-Funktion ist nicht mehr notwendig, da die Methode readAndStoreData des Objekts 't' in einem eigenen Thread gestartet wird.

    Gruß
    Werner



  • Jo.
    Wobei man Test::readAndStoreData und Test::getNr jetzt noch thread-safe machen müsste.


Anmelden zum Antworten