pthreads Thread wird nicht gestartet



  • Hi,
    Ich bin noch neu in der Linux programmierung(komme von Windows), habe mir jetzt CB unter Linux eingerichtet und benötige nun Threads für mein Programm. Habe mich dan für die pthreads entschieden. Hab jetzt nur das Problem das er die Threads nicht startet sondern einfach in der main weiterläuft.
    Code:

    #include <pthread.h>
    using namespace std;
    void *thread1(void *arg)
    {
    cout << "THREAD1" << endl;
    }
    void *thread2(void *arg)
    {
    cout << "THREAD2" << endl;
    }
    int main()
    {
        pthread_t t1, t2;
        long int i1, i2;
        int it1,it2;
        it1 = pthread_create(&t1, NULL, thread1, &i1);
        it2 = pthread_create(&t2, NULL, thread2, &i2);
    cout << "MAIN" << endl;
        return 0;
    }
    

    Also es wird nur MAIN ausgegeben aber die anderen beiden Sachen nicht!

    MFG ReduX



  • Der Thread wird bestimmt erzeugt, kommt aber nicht zur ausführung, da du das Programm zuvor schon beendest.



  • Hi,
    Danke für deine Antwort.
    1.)Also könnte ich dann auf diese Weiße mehrere Threads erstellen, gibt es da eigentlich ein Limit?
    2.) Kann ich eigentlich auch andere sachen als void* an eine funktion übergeben bzw. auch mehrer z.b. an eine funktion: beispielfunktion(int zahl, char array[24])?

    MFG ReduX



  • zu 1) Es gibt wohl durchaus ein Limit aber ich würde bezweifeln, dass du dort jemals ankommst 😉

    1. Direkt kannst du nur void übergeben. Das hindert dich natürlich nicht daran sowas zu machen:
    #include <pthread.h>
    #include <iostream>
    using namespace std;
    
    struct data {
        int zahl;
        char array[24];
    };
    
    void *thread1(void *arg)
    {
        cout << "THREAD1" << endl;
        cout << static_cast<data*>(arg)->zahl << static_cast<data*>(arg)->array << std::endl;
    }
    void *thread2(void *arg)
    {
        cout << "THREAD2" << endl;
    }
    int main()
    {
        pthread_t t1, t2;
        long int i1, i2;
        data foo;
        int it1,it2;
        it1 = pthread_create(&t1, &foo, thread1, &i1);
        it2 = pthread_create(&t2, NULL, thread2, &i2);
    cout << "MAIN" << endl;
        return 0;
    }
    

    Wenn dir das zu hässlich ist, bau dir einfach eine wrapper-Funktion



  • Nabend,

    du musst natuerlich noch auf die Beendigung des Threads warten. Das ist doch
    die Natur von Threads, dass sie unabhaengig vom Programm laufen.

    man pthread_join

    gruss
    v R



  • soweit ich weiß, ist die maximale anzahl an threads im gesamten system der wert von /proc/sys/kernel/threads-max. der ist aber zur laufzeit änderbar.



  • Ich würde ans Ende jeder Funktion (auch der main ) einfach ein pthread_exit(NULL) setzen, des ermöglicht, dass z.b. die main wartet, bis alle Threads zu Ende gelaufen sind und sich erst dann beendet. Im Übrigen, wenn du mit pthread_join arbeitest, kannste als Argument von pthread_exit() deinen Rückgabe-Wert setzen. Wie das genau geht, ist auch in Manpages nachzulesen (zur Not die manpages-dev nachinstallieren).



  • Hi,
    Danke für eure Antworten.
    Wenn ich es mit den static_cast mache bekomme ich beim übergeben des structs auf pthread_create folgenden Fehler:

    data*« kann nicht nach »const pthread_attr_t*« für Argument »2« nach »int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)« umgewandelt werden
    

    In dem struct ist ein integrer und ein char array!

    MFG ReduX :xmas1:



  • Was genau verstehst du von der Fehlermeldung nicht?

    pthread_chreate nimmt 4 argumente.

    #1 ist der Thread den du erzeugen willst.
    #2 Sind die Attribute des Threads ie »Joinable«
    #3 ist die Funktion, die der Thread ausführen soll
    #4 ist das Argument das du an die Funktion weitergeben willst.

    Wenn du als 2. Parameter eine eigene Struct verwenden willst ist das schlichtweg FALSCH, dafür ist der 4. Parameter da.



  • Hi,
    Danke für deine Hilfe.
    Wenn ich das so abändere bekomme ich folgenden Fehler:

    Fehler: Argument des Typs »void* (ldp::client::)(void*)« passt nicht zu »void* (*)(void*)«
    

    Habe es aber genau so gemacht wie es weiter oben gepostet wurde!

    MFG ReduX :xmas1:



  • Du kannst als Thread-Funktion nur statische Memberfunktionen und Gelöste Funktionen verwenden. »Normale« Klassenfunktionen funktionieren hier nicht. (Du kannst höchstens als 4. Parameter einen Zeiger auf ein Objekt übergeben und über diesen Zeiger wieder eine Klassenfunktion starten.



  • Hi,
    Also bei mir ist es so das die threads in der klasse gestartet werden, dann ist die Klassenfunktion für sie doch ganz normal oder?
    Bsp.:

    struct data {
    char array[4096];
    int len;
    compile func;
    }
    class MEINECLASSE {
    private:
    void* empfangen(void *arg); //compile ist ein typedef für einen Funktionszeiger!
    public:
    void* empfang(compile funktion); //In dieser Funktion werden die Threads gestartet,diese rufen dann empfangen auf!
    };
    

    MFG ReduX :xmas1:



  • Eine Klassenfunktion hat einen impliziten Parameter: Den this-Pointer. Da die pthread-Bibliotek keinerlei Ahnung von C++ hat (ein C Bibliotek ist) kann sie auch den this-Pointer nicht mit übergeben -> nur staische Klassenmember (haben keinen this-Pointer!) und globale Funktionen können direkt gestartet werden.

    Workaround:

    class Threaded
    {
    public:
      void start_thread() {pthread_create([], [], &helper, this);}
    private:
      static void helper(void * ptr){static_cast<Threaded>(ptr)->thread_fun();}
      void thread_fun();
    }
    
    int main()
    {
      Threaded foo;
      foo.start_thread();
      pthread_exit(0);
    }
    


  • Wenn du schon C++ verwendest, wieso nutzt du nicht alle Vorteile von C++? Anstatt einfach Boost::Thread zu verwenden, plagst du dich mit C-threads rum?



  • Hi,
    Ja ich möchte möglichst keine fremden libs verwenden. Außerdem geht es mir noch um den lern-Faktor. Ich will nicht einfach das Programm fertig haben, sondern möchte dabei etwas lernen.

    MFG ReduX :xmas1:



  • @ReduX: das is echt die richtige einstellung 🙂



  • DEvent schrieb:

    Wenn du schon C++ verwendest, wieso nutzt du nicht alle Vorteile von C++? Anstatt einfach Boost::Thread zu verwenden, plagst du dich mit C-threads rum?

    boost::thread war im Umfang das letzte mal als ich mir das angesehen habe noch recht eingeschränkt 😉



  • Hi,
    Irgendwie habe ich nun keine Idee mehr, ich habe mir mal das workaround vorgenommen das gepostet wurde und das ist dabei herausgekommen:
    Header:

    struct data {
      char array[4096];
      int len;
      compile funktion;
    };
    class client {
      private:
    //blabla
     static void* helprecive(void *arg);
     static void* helpsend(void *arg);
     void emfpange(compile func);
     void sending(char buffertosend[4096]);
      public:
    //blabla
    void send2server(char buffertosend[4096]);
    void recv2server(compile func);
    };
    

    CPP:

    void network::client::send2server(char buffertosend[4096]) {
        data foo;
        int t = strlen(buffertosend);
        for(int i=0;i<t;i++) {
        foo.array[i]=buffertosend[i];
        }
        #ifdef WIN32
    
        #else
        pthread_t t1;
        pthread_create(&t1,0,helpsend,&foo);
        #endif
    }
    static void* network::client::helpsend(void* arg) {
        sending(static_cast<data*>(arg)->array);
    }
    void network::client::sending(char buffertosend[4096]) {
     //blabla
    }
    void network::client::recv2server(compile func) {
        if(empfange == false) {
        data funktion;
        funktion.funktion = func;
        #ifdef WIN32
    
        #else
        pthread_t t1;
        pthread_create(&t1,0,helprecive,&funktion);
        #endif
        }
    }
    static void* network::client::helprecive(void* arg) {
    compile func = static_cast<data*>(arg)->funktion;
    empfange(func);
    }
    void network::client::empfange(compile func) {
    //blabla
    func(recvbuffer,strange);
    }
    

    Werde dabei mit Fehlermeldungen überflutet:

    /home/server/Desktop/networklib/network.cpp:43: Fehler: Elementfunktion »static void* network::client::helpsend(void*)« kann nicht deklariert werden, statische Bindung zu haben
    /home/server/Desktop/networklib/network.cpp: In static member function »static void* network::client::helpsend(void*)«:
    /home/server/Desktop/networklib/network.cpp: At global scope:
    /home/server/Desktop/networklib/network.cpp:61: Fehler: Elementfunktion »static void* network::client::helprecive(void*)« kann nicht deklariert werden, statische Bindung zu haben
    /home/server/Desktop/networklib/network.h: In static member function »static void* network::client::helprecive(void*)«:
    /home/server/Desktop/networklib/network.h:28: Fehler: ungültige Verwendung des Elementes »network::client::empfange« in statischer Elementfunktion
    /home/server/Desktop/networklib/network.cpp:63: Fehler: von dieser Stelle
    /home/server/Desktop/networklib/network.cpp: At global scope:
    /home/server/Desktop/networklib/network.cpp:65: Fehler: keine Elementfunktion »void network::client::empfange(void (*)(char*, int))« in Klasse »network::client« deklariert
    /home/server/Desktop/networklib/network.cpp: In member function »void network::client::empfange(void (*)(char*, int))«:
    /home/server/Desktop/networklib/network.cpp:66: Fehler: invalid use of member (did you forget the »&« ?)
    /home/server/Desktop/networklib/network.cpp:69: Fehler: invalid use of member (did you forget the »&« ?)
    

    Habe da den Durchblick verloren 😞

    MFG ReduX :xmas1:



  • Du kannst aus der statischen Funktion keine »normalen« Memberfunktionen aufrufen.

    Daher auch der Vorschlag this als argument zu übergeben, da du static_cast<Server>(this)->funktion() aufrufen kannst.



  • Hi,
    Wie kann ich dann aber Parameter übergeben?
    Weil das was der User bei dem Funktionsaufruf übergibt brauch ich ja dann noch in der Funktion die vom Thread gestartet wird!

    MFG ReduX :xmas1:


Anmelden zum Antworten