Thread in einer c++ klasse aufrufen



  • Hallo,

    hab hier ein simples Tread Programm in C
    das funktioniert auch super. Aber eine Frage wie ruf ich ein Tread in einer C++ klasse auf???
    hab das unten probiert aber leider ohne erfolg
    weiss da jemand rat??

    danke mal
    oli22

    #include <pthread.h>
    #include <stdio.h>  // printf
    #include <unistd.h> // sleep
    #include <iostream>
    using namespace std;
    
     void* thread_function1(void*)
      { 
        cout<<"Thread 1 gestartet"<<endl;
        sleep(3); // 3 Sekunden warten
        cout<<"Thread 1 wird beendet"<<endl;
        return 0;
    }
    
    int main() {
    
      pthread_t thread1; // Die Variable, in der der Tread 'gespeichert' wird
    
      pthread_create( &thread1, NULL,thread_function1, NULL );
      sleep(1); // 1 Sekunde warten, damit der Thread seinen Text ausgibt
      cout<<"Hauptprogramm"<<endl;
    
      sleep(3);
      pthread_cancel(thread1);
    
      return 0;
    }
    

    Funktioniert einwandfrei
    nun mein Versuch in C++

    #include <pthread.h>
    #include <stdio.h>  // printf
    #include <unistd.h> // sleep
    #include <iostream>
    using namespace std;
    
    class Sample
    {
      public:
    
      Sample(){}
    
       void* thread_function1(void*)
      { 
        cout<<"Thread 1 gestartet"<<endl;
        sleep(3); // 3 Sekunden warten
        cout<<"Thread 1 wird beendet"<<endl;
        return 0;
      }
    
      private:
    
    };
    
    int main() {
     Sample a;
    
      pthread_t thread1; // Die Variable, in der der Tread 'gespeichert' wird
    
      pthread_create( &thread1, NULL, a.thread_function1, NULL );  //wie ruf ich hier den tread in einer klasse auf???
      sleep(1); // 1 Sekunde warten, damit der Thread seinen Text ausgibt
      cout<<"Hauptprogramm"<<endl;
       sleep(3);
      pthread_cancel(thread1);
       return 0;
    }
    

    Fehlermeldung beim Kompilieren:
    In function int main()': test.cc:35: error: argument of typevoid*(Sample::)(void*)' does not
    match `void*()(void)'
    gmake: *** [DescriptorTest.o] Error 1



  • Hi, auch wenn das ganze thema hier schon über n jahr her is möcht ichs noch mal aufwirbeln, denn ich häng gerade an genau dieser stelle!

    hat jemand ne lösung dafür gefunden?



  • Eine nicht-statische Methode ist ein sogenannter "__thiscall"; d.h. der Funktion wird implizit die Adresse der Instanz mitübergeben.
    Dehalb ist "this" auch in jeder nicht-statische Memberfunktion verfügbar und in statischen (aka. Klassen-) Methoden nicht.

    Hab hier grade keine pthreads aber ich glaube da wird ein "__cdecl" erwartet - pthreads bilden ein "C"-API!

    Die Lösung ist eigentlich trivial:

    void* thread_function(void* pV) {
    
       Sample* pSample = reinterpret_cast<Sample*>(pV);
       return pSample->thread_function1(NULL);
    }
    

    Da wär ein ASSERT dann ggf. noch hilfreich.

    Das muss man dann aber mit einem auf void* runtergecasteten Sample*
    aufrufen; also hie z.B. &a:

    pthread_create( &thread1, NULL, thread_function,(void*) &a );
    

    Allerdings sollte a dann auf dem Heap liegen oder global sein; sonst knallt's nämlich beim Funktionsende des Ausgangsthreads wenn a destruiert wird!
    Das zöge dann dem neuen Thread die Sample-Instanz unter den Füssen weg! 🙂

    Grüsse

    *this



  • ok, mal abgesehn davon, dass ich dein quelltext da nich ganz versteh (von-java-umsteiger)
    hab ich nun das problem, dass der Thread von nem Objekt gestartet wird. also schon in einer "Klassen-Methode" und anschließend soll der Thread von demselben Objekt wiederum eine "Klassen-Methode" aufrufen:

    Server::Server(){
        serverSocket=socket(AF_INET, SOCK_STREAM, 0);
        if (serverSocket == -1){
            perror("socket() failed");
            return;
        }
        serverAdress.sin_addr.s_addr = inet_addr("127.0.0.1");
        serverAdress.sin_port = htons(80);
        serverAdress.sin_family = AF_INET;
    
        if (bind(serverSocket, (struct sockaddr*) &serverAdress, sizeof(serverAdress)) == -1){
            perror("bind() failed");
            return;
        }
        if (listen(serverSocket, 3) == -1){
            perror("listen () failed");
            return;
        }
    
        int client;
        for(;;){
            cliSize = sizeof(clientAdress);
            client = accept(serverSocket, (struct sockaddr*) &clientAdress, &cliSize);
            pthread_t thread;
            pthread_create(&thread,NULL,handleConnection,&client); // <<<<<<<<<<<<<<
            CLOSE(client);
        }
    }
    void *Server::handleConnection(void *_pclient){
        int client;
        client=(int)_pclient;
        cout << "client connected!" << endl;
        char buffer[] = "Willkommen auf dem Testserver";
        if(send(client, buffer, strlen(buffer), 0)==-1){
            printf("send() failed");
        }
    }
    

    die betreffende zeile ist mit // <<<<<<<<<<<<<< gekennzeichnet XD



  • DaHunger schrieb:

    ok, mal abgesehn davon, dass ich dein quelltext da nich ganz versteh (von-java-umsteiger)
    hab ich nun das problem, dass der Thread von nem Objekt gestartet wird. also schon in einer "Klassen-Methode" und anschließend soll der Thread von demselben Objekt wiederum eine "Klassen-Methode" aufrufen:

    Das ist etwas unscharf; in C++ gibt es Klassen- und Instanzmethoden. (Klassenmethoden sind "static" deklariert).

    Deshalb frag ich lieber erst mal nach:

    => Wie ist handleConnection() deklariert (im dem zug. Header)? <=

    Ferner sieht "class Server" sehr nach einem Singleton- http://www.vico.org/pages/PatronsDisseny/Pattern%20Singleton/index.html Kandidaten aus. Das könnte das Problem mit der Gültgkeit der als (void*) übergebenen Instanz auf einfachste Weise lösen!

    Desweiteren - hiermit

    void *Server::handleConnection()
    

    statt

    void* Server::handleConnection()
    

    versuchst Du nicht irgendetwas zu erreichen, oder?

    Grüsse

    *this



  • nein sie ist nich static

    class Server{
        public:
            Server();
            void *handleConnection(void *_client);
    

    also von der Server-Klasse wird schon nur 1 Objekt erzeugt,
    aber ist das nich total egal?

    das problem ist ja das selbe wie oben

    nur dass ich eben im Konstruktor von Server ein Thread starten will,
    der die Funktion handleConnection aufruft

    dass der stern rechts statt links is liegt nur daran,
    dass ich das bei variablen auch mache, der übersichtlichkeit halber...

    zb

    int* a,b
    

    kann verwirrung stiften gegenüber

    int *a,b
    

    aber sollte ja eigentlich keine bedeutung haben...

    genaugenommen hab ich den stern da ja eh nur hingemacht damit der thread zufrieden ist, ist er ja aber immer noch nicht xD

    Gruß Hunger

    edit:

    hier nochmal die fehlermeldung:

    :: === Socket, Server ===
    D:\Eigene Dateien\codeblocks\Socket\Socket.h:97: error: argument of type `void*(Server::)(void*)' does not match `void*(*)(void*)'
    :: === Build finished: 1 errors, 0 warnings ===
    


  • ok warum sagt mir keiner dass man keine pointer auf member-methoden machen kann XD
    problem halbwegs gelöst... ich kann darin jetzt nichts senden, aber das ist ein anderes problem XD

    auch dieses problem habe ich behoben der client war schon zu im konstruktor bevor der thread senden konnte danke dir gast++



  • Möglicherweise könnte jemand interessiern wie meine lösung ausschaut, daher erkläre ich sie jetzt:

    ausgangsproblem: in einer member-funktion soll ein thread gestartet werden, der einer andere member-funktion aufruft.

    lösung:

    man definiere eine statische funktion die für den thread passend ist:

    static void *stHandleConnection(void *_pclient);
    

    und die funktion die eigentlich aufgerufen werden soll:

    void handleConnection(int _client);
    

    der statischen funktion übergibt man als parameter ein pointer auf ein struct,
    in dem der eigentliche parameter steht, sowie ein zeiger auf das objekt:

    das Struct:

    struct serverClient{
        Server *server;
        int client;
    };
    

    und der thread-start:

    struct serverClient client;
    client.server= this;
    client.client= //... naja der parameter eben. .. bei mir: accept(serverSocket, (struct sockaddr*) &clientAdress, &cliSize);
    pthread_t thread;
    pthread_create(&thread,NULL,stHandleConnection,&client);
    

    und wie der aufruf der nicht-statischen funktion in der statischen aussieht:

    void *Server::stHandleConnection(void *_pclient){
        struct serverClient client;
        client=*(struct serverClient *)_pclient;
        Server sv=*client.server;
        sv.handleConnection(client.client);
    }
    

    das wars auch schon man muss eben die parameter an seine bedürfnisse anpassen, logischer weise...

    danke euch,
    Hunger



  • Schön dass es läuft, aber

    - Mit C++ werden automatische Variablen zersört wenn der Blcok durchlaufen ist; das ist anders als mit Java!
    Wenn Du im Hauptthread eine Instanz erzeugst ziehst Du sie ggf. dem neu erzeugten Thread so unter den Füssen weg.
    Bau lieber ein "Server"-Singleton; dann ist das Problem der Instanzkurzlebigkeit vom Tisch und das Muster ist hier sowieso naheliegend.

    - Ich hatte Dir das bewusst nicht mit einer statischen Funktion sondern mit einer freien Funktion gezeigt.
    Eine statische (Klassen-)Funktion zu verwenden macht nur dann Sinn wenn man etwas aus der Klasse verwenden muss; das tust Du hier aber gar nicht. Du verwendest einzig eine Zusicherung einer Instanzfunktion (des Konstruktors).
    Deshalb ist eine freie Funktion als Zugeständnis an das "C"-API semantisch viel klarer.

    - Du machst zuviel auf einmal im Konstruktor

    Btw man kann Funktionszeiger auch auf Memberfunktionen erhalten; zum Umgang damit sind die Operatoren "::" "->" und ".***" gedacht. Stroustrup C++PL §15.5
    Die nützen Dir aber nichts bei "C"-APIs.

    Grüsse

    *this



  • das programm da oben ist ja auch nur ein teste für sockets und threads.
    später wird es allerdings nötig sein dass es eine member-funktion ist,
    im moment sieht man davon nur noch nichts 😉 der Hauptthread endet doch nicht? wie soll ich dem thread dann die instanz "klauen"? sie ist ja vorhanden ich zersöre sie ja nicht...



  • DaHunger schrieb:

    das programm da oben ist ja auch nur ein teste für sockets und threads.
    später wird es allerdings nötig sein dass es eine member-funktion ist,
    im moment sieht man davon nur noch nichts 😉 der Hauptthread endet doch nicht? wie soll ich dem thread dann die instanz "klauen"? sie ist ja vorhanden ich zersöre sie ja nicht...

    void aFunction(void) {
        A a; // Konstruktor wird impizit aufgerufen
        /*
         * ...
         */
        pthread_create(&thread,NULL,thread_function,&a);
    } // a Destruktor wird impizit aufgerufen !
    

    Das was ich meiner hängt mit Blöcken zusammen.

    Wenn der Hauthread die Funktion abgearbeitet hat destruiert er das lokale "A" a.
    Der neue Thread nutzt aber die lokale Instanz (wie ich's gzeigt hatte und wie Du'S auch mittles der statischen Funktion benutzt) weiter - das geht iA. nicht gut!

    FErner solltest Du nicht im Konstruktor Threads auf Methoden des gerade konstruierten Objektes setzen.

    Grüsse

    *this



  • ich hab doch aber keine lokale instanz von server irgendwo?! ich geb dem ding doch ne referenz auf des objekt was am anfang erzeugt wurde. und da läuft ne endlosschleife ab die immer wieder nen neuen thread macht wenn ein client kommt...
    also existiert die instanz doch solange, wie das programm läuft?!


Anmelden zum Antworten