0

I want to spawn a thread from within my class but can't seem to find the correct formula to make pthread_create() happy.

My class looks like:

#ifndef _BFD_ENDPOINT_H_
#define _BFD_ENDPOINT_H_
#include <pthread.h>

using namespace std;

enum BfdState_e {
        BFD_STAT_ADMIN_DOWN = 0,
        BFD_STAT_DOWN,
        BFD_STAT_INIT,
        BFD_STAT_UP };


class BfdEndpoint {
   public:
        int RxIntvlSet(int);
        int TxIntvlSet(int);
        int MultSet(int);
        int ActvSet(bool);
        enum BfdState_e StatusGet();
        BfdEndpoint();  // constructor
        ~BfdEndpoint(); // destructor

   public:
        //configuration params
        int rx;         // Rx interval [us]
        int tx;         // Tx interval [us]
        int mult;       // multiplier
        bool active;    // active (1) or passive (0) endpoint
        //internal vars
        enum BfdState_e status;
        pthread_t *RxTh;
        pthread_t *TxTh;
        //internal methods
        int Start();
        void *RxSM(void);
        void *TxSM(void);

};
#endif

and the implementation of the respective function looks like:

void *BfdEndpoint::RxSM(void)
{
        return NULL;
}

int BfdEndpoint::Start(void)
{
        int rv = 0;
        rv = pthread_create(RxTh,NULL,&BfdEndpoint::RxSM,NULL);

}

and g++ is barking the following:

$ g++ *.cpp -o bfd
bfd.cpp: In member function ‘int BfdEndpoint::Start()’:
bfd.cpp:34:55: error: cannot convert ‘void* (BfdEndpoint::*)()’ to ‘void* (*)(void*)’ for argument ‘3’ to ‘int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)’
  rv = pthread_create(RxTh,NULL,&BfdEndpoint::RxSM,NULL);

How do I do this?

stdcerr
  • 13,725
  • 25
  • 71
  • 128
  • 1
    `_BFD_ENDPOINT_H_` is a reserved identifier (because it starts with underscore followed by uppercase). You should come up with another name for the include guard. – eerorika Jan 14 '17 at 20:15
  • 1
    You're run afoul of the hidden `this` parameter all member functions have. `void *RxSM(void);` looks to the compiler more like `void *RxSM(BfdEndpoint*);` – user4581301 Jan 14 '17 at 20:18
  • 1
    No, identifiers that contain two consecutive underscore are also reserved. `BFD_ENDPOINT_H_` would be fine. – eerorika Jan 14 '17 at 20:18
  • Possible duplicate of [pthread function from a class](http://stackoverflow.com/questions/1151582/pthread-function-from-a-class) – user4581301 Jan 14 '17 at 20:21

2 Answers2

1

pthread_create only accepts regular function pointers (or compatible) to create a thread. It is a limitation of a C compatible interface

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

The C++11 thread abstraction interface does support class member functions to be run as a thread. Of course a member function requires a pointer to an actual object (this pointer), so you will have to pass that to the thread object

BfdEndpoint object;
std::thread thr{&BfdEndpoint::memfunc, &object, ...};
LWimsey
  • 6,189
  • 2
  • 25
  • 53
1

Problem1: pthread_create expects a function that takes a void* as an argument. Your function doesn't accept a void* argument.

Problem2: pthread_create expects a function pointer. Applying address-of operator on a non-static member function results in a member function pointer. A member function pointer is not convertible to a regular function pointer.

Solution: Use a callback function that matches the function pointer signature that pthread_create expects. This means that you must use a free function (or a static member function).

You can call a member function on an object within that free function. A trivial example:

void* RxSM(void*) {
    static BfdEndpoint object;
    object.RxSM();
}

You may wish to call BfdEndpoint::RxSM on the object that created the thread instead. You can pass that object to the callback by using the fourth void *arg argument.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Interesting take on the lazy loader, but how does the code call `BfdEndpoint::Start` to set up the `pthread` in the first place? – user4581301 Jan 14 '17 at 20:31
  • @user4581301 you'd have to do that on another object. If OP wishes to call `BfdEndpoint::RxSM` on the same object that created the thread, then they will have to do some work and develop this further. – eerorika Jan 14 '17 at 20:34