Threads in Klassen



  • gut das wäre dann auch möglich muss ich den Code eben umstellen! Thx aber is schon bescheiden, dass dies nicht geht!



  • Kevinus schrieb:

    Wie kann ich dieses Problem lösen oder sind Threadfunktionen in Klassen nicht möglich???

    Möglich schon, nur, wie pZy schon sagte, keine Member-Funktionen. Du musst schon eine static Funktion dafür nehmen. Es gibt aber trotzdem eine recht einfache Möglichkeit für das, was du vorhast. Dazu übergibst du einfach this als Thread-Funktionsparameter.

    // Thread Erstellung - this_ ist die entsprechende Klasseninstanz, der du den Thread zuordnen willst
    CreateThread(NULL, 0, &foo::my_static_main, this_, 0, NULL);
    // deine Klasse
    class foo
    {
    public:
    	static DWORD WINAPI my_static_main(void* parameter)
    	{
    		foo* this_ = static_cast<foo*>(parameter);
    		this_->my_main();
    	}
    	void my_main()
    	{
    		// das ist deine eigentliche Thread-Funktion - nun als Member
    	}
    };
    


  • In Klasse:
    
    class X
    {
        // Kann public, protected oder auch private sein.
        protected: DWORD WINAPI Threadxyz (LPVOID lpParam);
        public:    void Threadaufrufer ();
    };
    
    Aufruf in x.cpp-Datei:
    
    void X::Threadaufrufer ()
    {
        HANDLE hThread;
        DWORD dwParam, dwThreadID = 1;
        hThread = CreateThread (NULL,
                                0,
                                Threadxyz,
                                &dwParam,
                                0,
                                &dwThreadID);
    }
    
    DWORD WINAPI X::Threadxyz (LPVOID lpParam)
    {
        //Threadfuntionen
    }
    


  • @Fiesek
    Wenn du schon Code postest, dann solltest du ihn vorher vielleicht testen. 😉 Dann wäre dir vielleicht auch aufgefallen, dass es _so_ nicht geht. Aber das hatten wir ja eigentlich schon festgestellt, denn genau um dieses Problem ging es ja dem OP.



  • 😃 😃





  • Da kann ich dir nur teilweise zustimmen, dass mein Code nicht funzt.

    Ich hab mir also nen Thread zum Senden von Zeichen über die RS232 geschaffen und zwar so wie von mir oben beschrieben.
    Compiliert, keine Fehler.

    Dann hab ich einen weiteren Thread hinzugefügt zum Empfangen von Zeichen über die RS232, da hab ich dann auf einmal auch Fehlermeldungen.

    Ich werd dem Problem nochmal genauer auf den Pelz rücken und dann meine Erkenntnisse kundtun.



  • Dein Beispiel als vollständiges Programm ergibt:

    #include <windows.h>
    #include <tchar.h>
    #include <stdio.h>
    
    class X
    {
      protected: 
        DWORD WINAPI Threadxyz (LPVOID lpParam)
        {
        }
      public:    
        void Threadaufrufer()
        {
          HANDLE hThread;
          DWORD dwParam, dwThreadID;
          hThread = CreateThread (NULL, 0, Threadxyz, &dwParam, 0, &dwThreadID);
        }
    };
    
    int _tmain()
    {
      X x;
      x.Threadaufrufer();
    }
    

    Was sich definitiv nicht übersetzen lässt!



  • Fiesek schrieb:

    Da kann ich dir nur teilweise zustimmen, dass mein Code nicht funzt.

    Es geht nicht darum, ob du mir zustimmst oder nicht. Dein Code ist falsch. Punkt. Und wenn dein Compiler das übersetzt, dann ist er diesbezgl. kaputt.
    Und wenn du das noch immer nicht akzeptierst, dann beantworte mir doch mal folgende Frage:
    Wie du sicherlich weisst, liegt jeder Member-Funktion (in deinem Fall X::Threadxyz) ein Objekt zu Grunde. Dieses lässt sich in der Funktion über this ansprechen und wird ausserhalb beim Aufruf explizit angegeben. Da CreateThread genau das macht, dh X::Threadxyz irgendwann aufruft, muss es also ein Objekt geben. Ich sehe in deinem CreateThread Aufruf allerdings keines. Du etwa? Und &X::Threadxyz, wie es übrigens korrekterweise heissen muss, ist nur ein Funktionszeiger. Mit Objekt is hier nix.



  • Sry, ihr habt recht, ich hab unrecht.
    Mein Code funzt definitiv nicht!



  • So, ich hab meine Threads jetzt static gemacht und siehe da, es funzt.

    Wichtig dabei:

    static nur in der Deklaration angeben,
    der Thread kann nun nicht mehr auf Elementfunktionen und Membervariablen der eigenen Klasse zugreifen.

    Ich hab meinen Threads dann ein Array von Pointern auf meine Membervariablen mitgegeben.
    So ließ es sich dann fehlerfrei compilieren.



  • Du hast dir aber schon meinen ersten Beitrag durchgelesen? Dort hab ich doch erklärt, wie du eine Memberfunktion für deine Threadfunktion verwenden kannst und damit auch auf Membervariablen zugreifen kannst.



  • Hab im Moment etwas ähnliches am Laufen: Meine Threadfunktion ist als statische Methode in meiner Klasse, jedes Objekt hat eine Funktion zum Starten des Threads. Dabei wird natürlich immmer ein Zeiger zum Objekt selbst übergeben.
    In der Threadfunktion befindet sich eine Endlosschleife.
    Meine Frage: Können diese Objekte nun tatsächlich unabhängige Threads haben? Will heißen laufen parallel mehrere Aufrufe der statischen Funktion und wenn ja, wie hängen diese zeitlich miteinander zusammen?



  • Wenn Du mehrere Threads startest, dann laufen auch mehrere! Zeitlich hängen die gar nicht zusammen. Wenn Du was synchronisieren musst, dann musst Du dies selber machen... (CriticalSections, Events, ...)



  • Das ist mir schon klar, ist in dem Falle nicht einmal nötig.
    Mir ging es nur um die Frage ob die Threads der einzelnen Objekte unabhängig laufen, obwohl es ja die gleiche statische Funktion ist und diese sozusagen mehrmals gleichzeitig läuft.



  • Wenn Du unterschiedliche Pointer auf die Klasse übergeben hast (also "this"), dann hat ja die statische Thread-Funktion auch diesen Pointer. Somit verwendet jeder Thread die Klasse welche Du übergeben hast. Da dies ja ein Parameter ist, der auf dem Stack liegt und jeder Thread seinen eigenen Thread hat ist sie in jedem Thread eben anders (wenn Du was anderes übergeben hast).



  • Ich habe mal eine kleine Testklasse für so etwas geschrieben um das mal zu beobachten:

    class ThreadObject{
      public:
        ThreadObject(int _id, HWND _hParent) { id = _id; hParent = _hParent;};
        void startWatch(void)
        {
            _beginthread(appWatch,0,(void *)this);
        }
    
      private:
        int id;
        HWND hParent;
    
        static void appWatch(void *tObject)
        {
          ThreadObject *obj = static_cast<ThreadObject*>(tObject);
    
          for(;;){
            Sleep(500 + (rand() % 5) * 100);
            SendMessage(obj->hParent,WM_THREAD_OBJECT_NOTIFY,(WPARAM)obj->id,NULL);
          }
        }
    };
    

    Sorry wegen der Klassen, ist aber in eine normale WinAPI Anwendung eingebettet.

    Man holt sich mit

    ThreadObject *obj = new ThreadObject(1001,hwnd);
    obj->startWatch();
    

    (Sorry wegen new 😃 )

    ein ThreadObject und startet mit startWatch() den Thread dieses Objekts. Der Thread eines jeden Objekts schickt nun in relativ zufälligen Abständen eine Nachricht mit seiner id an das Hauptfenster, welches diese recht simpel ausgibt.

    Dabei ist beim Benutzen von mehr als einem Objekt zu beobachten, dass die Nachrichten der Objekte immer stoßweise ankommen. Also zb so:

    Nachricht id 1; 
    Nachricht id 2; 
    Nachricht id 3;
    
    [600 millisec vergehen]
    
    Nachricht id 1;
    Nachricht id 2;
    Nachricht id 3;
    
    [1000 millisec vergehen]
    
    Nachricht id 1;
    Nachricht id 2;
    Nachricht id 3;
    
    [1100 millisec vergehen]
    
    Nachricht id 1;
    Nachricht id 2;
    Nachricht id 3;
    

    Die Abstände sind zufällig, jedoch sind sie bei allen Objekten gleich. Liegt das vielleicht sogar daran, dass der Zufallsgenerator bei paralellen Aufrufen die gleiche Zahl ausspuckt? Kann ich mir nicht vorstellen.



  • Du hast vergessen den rand zu initialisieren, deswegen liefert er in allen Thread immer die gleichen Abfolgen an Zahlen und somit treten die Events immer gleichzeitig ein...
    =>

    static void appWatch(void *tObject)
        {
          ThreadObject *obj = static_cast<ThreadObject*>(tObject);
    
          srand( (unsigned)time( NULL ) );
    
          for(;;){
            Sleep(500 + (rand() % 5) * 100);
            SendMessage(obj->hParent,WM_THREAD_OBJECT_NOTIFY,(WPARAM)obj->id,NULL);
          }
        }
    


  • Sorry, wollte nicht den ganzen Code posten.
    randomize() wird in WM_CREATE aufgerufen!



  • Du musst den random in *jedem* Thread initialisieren! Also bringt es nix wenn Du dies in WM_CREATE machst (da dies ja ein ganz anderer Thread ist!).
    Auch wenn Du es in dem Thread machst, und Du die Threads ganz schnell hintereinader startest, kann es sein dass der gleiche Seed verwendet wird.... also füge noch irgendein globaler Zähler hinzu...


Anmelden zum Antworten