简体   繁体   中英

Calling a class member function from a thread using pthread_create

Below is the code

#include <iostream>
#include <pthread.h>

using namespace std;

class Base

{
    private:
    public:

        void *threadCall1( void * value)
        {
            cout<<"inside threadCall1"<<endl;

        }

    protected:

};

class Derived
{
    private:
    public:
        void  *threadCall2 ();
    protected:



};


 void *Derived::threadCall2()
{
    cout<<"inside threadCall2"<<endl;

}
int main ()
{
    int k = 2;
    pthread_t t1;
    cout<<"inside main"<<endl;
    Base *b = new Base();

    pthread_create(&t1,NULL,&b->threadCall1,(void *)k);

    return 0;
}

Error

main.cc: In function int main()': main.cc:46: error: ISO C++ forbids taking the address of a bound member function to form a pointer to member function. Say int main()': main.cc:46: error: ISO C++ forbids taking the address of a bound member function to form a pointer to member function. Say &Base::threadCall1' main.cc:46: error: cannot convert void*(Base::*)(void*)' to void*( )(void )' for argument 3' to int pthread_create(pthread_t*, const pthread_attr_t*, void*( )(void ), void*)'

I agree C++ forbids this call but is there any way I can call a class member function using posix thread

There's no such thing as &b->threadCall1 . Fortunately, pthread allows you to pass a void ptr to the class (the one you're filling with k). Pass b as this void ptr to a global (or static member) function that simply calls b->threadCall1(); then move k to an attribute of Base instead of an argument of Base::threadCall1().

You can do this via a function that dispatches the work accordingly:

#include <iostream>
#include <pthread.h>

struct Base {
    virtual void work() {
        std::cout << "Base::work()\n";
    }

    virtual ~Base() {}
};

struct Derived : public Base {
    void work() override {
        std::cout << "Derived::work()\n";
    }
};

void* thread_adapter(void* obj) {
    Base* p = static_cast<Base*>(obj);
    p->work();
    return nullptr;
}

int main() {
    Derived d;
    pthread_t thread;
    pthread_create(&thread, nullptr, thread_adapter, &d);
    pthread_join(thread, nullptr);
}

Live example

pthread_create accepts a pointer to arbitrary data for the thread function. Pass the address of your object, and use a forwarding function such as the thread_adapter defined above. Inside the adapter function, you can static_cast the argument back to a Base* inside your thread function and invoke the member function as desired.

However, you may want to look into the std::thread library, which supports such operations in a more natural way:

#include <iostream>
#include <thread>

struct Base {
    virtual void work() {
        std::cout << "Base::work()\n";
    }

    virtual ~Base() {}
};

struct Derived : public Base {
    void work() override {
        std::cout << "Derived::work()\n";
    }
};

int main() {
    Derived d;
    std::thread t(&Base::work, d);
    t.join();
}

Live example

You cannot use pointer to member function as thread routine. Consider to use thead context structure to pass need information to the thead routine:

struct thread_context {
  Base* object;
  void (Base::*func)(void*);
};

void *thread_routine(void *arg) {
   thread_context* context = static_cast<thread_context*>(arg);
   context->object->(*context->func)(nullptr);
   ...
}

...
thread_context context = {
   b1,
   &Base::threadCall1
};
pthread_create(&t1,NULL,&thead_routine, &context);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM