Reputation: 1940
i have a Base class and Derived class. they have a virtual function- virtual void action() how can i pass it to *pthread_create()* function?
example(with errors):
class Base{
protected:
pthread_t tid;
public:
virtual void* action() = 0;
};
class Derived : public Base{
void* action();
Derived(){
pthread_create(&tid, NULL, &action, NULL);
}
};
maybe it should be static? i tried lot of combinations but cant find solution..
Upvotes: 4
Views: 9417
Reputation: 2487
I ran into this problem a couple months back working on my senior design project. It requires some knowledge of underlying C++ mechanics.
The underlying issue is that pointers to functions are different from pointers to member functions. This is because member functions have an implicit first parameter, this
.
From the man
page:
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine) (void *),
void *arg);
The thread entrance point is a void* (*)(void*)
. Your function, Base::action
has the type void* (Base::*)()
. The Base::
part of that ugly type declaration denotes the type of this
. The type discrepancy is why the compiler won't accept your code.
There's two things we need to fix to make this work. We can't use a member function, because pointers to member functions don't bind this
to an instance. We also need a single parameter of type void*
. Thankfully, these two fixes go hand in hand because the solution is to explicitly pass this
ourselves.
class Base {
public:
virtual void* action() = 0;
protected:
pthread_t tid;
friend void* do_action(void* arg) {
return static_cast<Base*>(arg)->action();
}
};
class Derived : public Base {
public:
Derived() {
// This should be moved out of the constructor because this
// may (will?) be accessed before the constructor has finished.
// Because action is virtual, you can move this to a new member
// function of Base. This also means tid can be private.
pthread_create(&tid, NULL, &do_action, this);
}
virtual void* action();
};
Edit: Woops, if tid
is protected
or private
, then do_action
needs to be a friend
.
Upvotes: 4
Reputation: 108
I usually do something similar to this, I'll let you fill in the other details (error handling, locking, etc):
Start method:
bool pthreadBase::start()
{
return pthread_create(&threadID, NULL, &execute,this);
}
Static void* Execute method:
void *pthreadBase::execute(void *t)
{
reinterpret_cast<pthreadBase *> (t)->processLoop();
return NULL;
}
After, you can just make a virtual method called processLoop that will act as an entry point for your thread.
Here's a simple implementation (NOT TESTED):
class theThread: public pthreadBase
{
public:
theThread(SharedMemoryStructure *SharedMemory)
{
_Running = start();
_Shared = SharedMemory;
}
~theThread()
{
stop(); //Just do a join or something
_Running = false;
}
private:
void processLoop()
{
while(_Shared->someQuitFlag() == false)
{
/*Do Work*/
}
}
private:
bool _Running;
SharedmemoryStructure *_Shared;
};
Upvotes: 1
Reputation: 12489
You have to have a function that takes one void pointer to pass to pthread_create
. I'd write the function myself, as a function that takes a pointer to Base
(Derived
would work as well), then call the action
function of the parameter. You can then create a thread that runs the function and received this
as parameter:
void *f(void *param)
{
Base* b = (Base *)param;
return b->action();
}
class Derived : public Base{
void* action();
Derived() {
pthread_create(&tid, NULL, f, this);
}
};
Upvotes: 3
Reputation:
Indeed it has to be static. You'll also need to pass your object as an argument to pthread_create:
void *Base::static_action(void *v)
{
((Base*)v)->action();
return NULL;
}
pthread_create(&tid, NULL, &Base::static_action, myObject);
Upvotes: 2
Reputation: 490218
Making it static isn't really guaranteed to work, but actually does at least with most implementations (and enough people depend on it that I'd be a little surprised to see that change soon either).
Upvotes: 0