C ++: how to define a class method as a trigger for a thread (using the pthread library)

I have a Base class and a Derived class. they have a virtual function - a virtual action void () how can I pass it to the * 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 many combinations, but could not find a solution.

+4
source share
5 answers

I ran into this problem a couple of months ago while working on my senior project project. This requires some knowledge of the underlying mechanics of C ++.

The main problem is that function pointers are different from member function pointers. This is because member functions have an implicit first parameter, this .

On the man page:

 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); 

Thread entry point void* (*)(void*) . Your Base::action function is of type void* (Base::*)() . The Base:: this ugly type declaration denotes the this type. The type difference is why the compiler does not accept your code.

We have to fix two things to make this work. We cannot use a member function because pointers to member functions do not bind this to an instance. We also need a single parameter of type void* . Fortunately, these two corrections go hand in hand, because the solution is to explicitly pass this yourself.

 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 should be friend .

+4
source

You must have a function that takes one void pointer to go to pthread_create . I will write a function myself, because a function that takes a pointer to Base ( Derived will work too), then call the action function of this parameter. Then you can create a thread that runs the function and get this as a 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); } }; 
+3
source

Indeed, it must be static. You 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); 
+2
source

I usually do something similar to this, I will let you fill in other details (error handling, blocking, etc.):

Launch method:

 bool pthreadBase::start() { return pthread_create(&threadID, NULL, &execute,this); } 

Static void * Run method:

 void *pthreadBase::execute(void *t) { reinterpret_cast<pthreadBase *> (t)->processLoop(); return NULL; } 

After that, you can simply create 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; }; 
+1
source

Making it static is not really guaranteed, but in fact it is, at least, with most implementations (and enough people depend on it that I would be a little surprised to see this change too).

0
source

All Articles