Probleme mit posix-thread



  • Hallo,

    ich habe ein Problem bei der Thread-Programmierung.
    Und zwar möchte ich pthread_create(..) innerhalb einer Klasse aufrufen.
    Das funktioniert irgendwie nicht richtig, obwohl die gleiche Art der Anwendung in einer C-Bibliothek problemlos läuft (natürlich ohne Klasse).

    Gibt es da bekannte generelle Probleme ?

    Der Funktionsaufruf innerhalb der Klasse sieht so aus :

    void CDisplay::StartThread(void)
    {
    if(!bThreadStart)
    {
    pthread_create(&ThreadID, NULL, &ThreadFunction, NULL);
    }
    }

    An Parameter 3 meckert der Compiler ständig rum, auch wenn ich dort z. B.
    einen Cast mache wie z. Bsp. "(void*)ThreadFunction".

    Der Prototyp von "ThreadFunction" ist "void* ThreadFunction(void)".

    Was mache ich verkehrt ?
    Wie gesagt, der Aufruf und die Kreierung sollen in einer Klasse bzw. in deren Memberfunktionen ablaufen. 🙂

    Danke für eure Hilfe.



  • Der dritte Parameter muss eine statische Funktion sein, die keinen Parameter hat und einen Zeiger auf void zurückgibt. Tut das deine?
    Merke: Eine Memberfunktion kannst du da nicht angeben! (ausser sie ist statisch).



  • drakon schrieb:

    Der dritte Parameter muss eine statische Funktion sein, die keinen Parameter hat und einen Zeiger auf void zurückgibt.

    Nur eine kleine Ergänzung/Berichtigung dazu: Die Funktion, die als Thread laufen soll, hat einen Pointer als Parameter, also z.B.

    void* CDisplay::StartThread(void *arg);
    

    Was man in dieser Situation häufig macht ist, den this-Zeiger als letztes Argument von pthread_create() zu übergeben. Dieser wird dann als Argument an die Thread-Funktion weitergegeben. Die Funktion kann ihn nach CDisplay* zurück casten, um trotz static an den this-Zeiger ranzukommen.



  • dooooomi schrieb:

    drakon schrieb:

    Der dritte Parameter muss eine statische Funktion sein, die keinen Parameter hat und einen Zeiger auf void zurückgibt.

    Nur eine kleine Ergänzung/Berichtigung dazu: Die Funktion, die als Thread laufen soll, hat einen Pointer als Parameter, also z.B.

    void* CDisplay::StartThread(void *arg);
    

    Danke, das wusste ich nicht. Ich habe einfach mal angenommen, dass die Fehlermeldung stimmt. 😉

    Dem Fall ist es, wie du richtig sagst kein Problem den this Zeiger explizit anzugeben und zu casten. (nervig wäre es, wenn die wirklich void wäre. :))



  • vielen Dank für eure Antworten. Wenn ich das richtig verstehe, dann muss also die Thread-Fkt. statisch sein, dann darf diese auch eine Member-fkt. der Klasse darstellen. Das Dumme dabei ist halt nur, dass eine statische Fkt. ja auch nur statische Elemente enthalten darf, un das ist halt in der Fkt., die im Thread laufen soll leider nicht der Fall. Das würde also heissen, dass ich den Thread sozusagen "aussen vor" (nicht in einer Klasse" definieren muss, oder ?
    Z. B. als c- Datei, die ich dann dort einbinde.
    Kann nicht sagen, dass ich das toll finde.
    Gibt es da noch "echte" c++ - Alternativen ??

    Danke.



  • schubi schrieb:

    vielen Dank für eure Antworten. Wenn ich das richtig verstehe, dann muss also die Thread-Fkt. statisch sein, dann darf diese auch eine Member-fkt. der Klasse darstellen. Das Dumme dabei ist halt nur, dass eine statische Fkt. ja auch nur statische Elemente enthalten darf, un das ist halt in der Fkt., die im Thread laufen soll leider nicht der Fall.

    Wie meinst du das, "nur statische Elemente"? Im Prinzip gibt es nur einen einzigen Unterschied zwischen statischen und nicht-statischen Memberfunktionen, nämlich daß du in den statischen keinen this-Zeiger hast (ist ja auch klar, weil die Funktion ja auf kein konkretes Objekt aufgerufen wird). Und wie du in der statischen Funktion an den this-Zeiger kommst habe ich oben schon beschrieben.

    Was du wohl machen kannst, ist den Thread als normale Memberfunktion zu schreiben, und dann eine kleine statische Memberfunktion als Wrapper. Das würde dann etwa so aussehen:

    class CDisplay
    {
        void ThreadFunktion();
        static void* ThreadFunctionWrapper(void *arg);
        void StartThread();
    };
    
    void CDisplay::ThreadFunction()
    {
        // das hier ist eine ganz normale Member-Funktion
        // ...
    }
    
    void* CDisplay::ThreadFunctionWrapper(void *arg)
    {
        CDisplay *this_ = static_cast<CDisplay*>(arg);
        this_->ThreadFunction();
    }
    
    void CDisplay::StartThread()
    {
        // hier werden die Wrapper-Funktion und der this-Zeiger als Parameter angegeben
        pthread_create(&ThreadID, NULL, &ThreadFunctionWrapper, static_cast<void*>(this));
    }
    


  • Man sollte noch anmerken, dass eine Thread-Funktion nicht die statische Funktion einer Klasse sein sollte, sondern eine freie extern "C" Funktion. Denn nirgends steht geschrieben, dass eine statische Funktion dieselben Calling Conventions haben muss, wie eine freie extern "C" Funktion.

    Ist aber nicht wirklich ein Problem.

    extern "C" void* FreeThreadFunctionWrapper(void* arg)
    {
        CDisplay::ThreadFunctionWrapper(arg);
    }
    

Anmelden zum Antworten