bob
bob

Reputation: 2101

c++ thread issue

I'm trying to create a thread in c++ with this code:

pthread_t mythread;
void* f (void*) = MyClass::myfunction;
pthread_create(&mythread, NULL, &f, NULL);

It's not working. Any idea what's wrong ?

myfunction is of type:

void* MyClass::myfunction(void* argv);

The error returned is:

error: declaration of ‘void* Class::f(void*)’ has ‘extern’ and is initialized

error: invalid pure specifier (only ‘= 0’ is allowed) before ‘::’ token

error: function ‘void* Class::f(void*)’ is initialized like a variable

Upvotes: 2

Views: 436

Answers (3)

Mike Seymour
Mike Seymour

Reputation: 254751

You're declaring f as a function rather than a function pointer. It should be:

void* (*f) (void*) = &MyClass::myfunction;
      ^^^^

pthread_create(&mythread, NULL, f, NULL);
                                ^ no & since it's already a pointer

This will also only work if myfunction is static, since you can't convert a pointer-to-member-function to a pointer-to-function.

If you do need to the thread to execute a non-static member function on a particular object, then one approach is to write a static wrapper taking the object as an argument:

class MyClass {
public:
    void start_thread() {
        // Pass "this" to the thread we're creating
        pthread_create(&mythread, NULL, &MyClass::thread_entry, this);
    }
private:
    static void * thread_entry(void * object) {
        // Call the member function on the object passed to the thread
        return static_cast<MyClass*>(object)->thread();
    }
    void * thread() {
        // do the interesting stuff, with access to the member variables
    }
};

Of course, these days there's a standard thread library which removes the need for this dance:

std::thread thread(&MyClass::thread, this);

Upvotes: 6

Kos
Kos

Reputation: 72319

Pthreads expects a function pointer, and with classes, you can only point to a static method using a function pointer.

If you'd like to call a specific method of a class on a specific object, you need two separate parts of data:

  • pointer to a class method (don't confuse them with function pointers)
  • pointer to an object

These two joined together can be informally called a delegate.


PThreads is a C library, and to interoperate with it, you need a little workaround:

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

We're going to wrap the class method in a static class method, to be able to pass it as parameter start_routine, and we're going to pass the pointer to the object itself as arg.

See the code:

struct Foo {

    // wrapper method
    static void* threadStartingPoint(void* obj) {
        return ((Foo)obj)->threadFunc();
    }

    // your target method itself
    void* threadFunc() {
        // this is where you do your logic
    }
}

Such workaround allows you to use pthread_create(thread, attr, Foo::threadStartingPoint, someObject).


Note that if you are lucky enough to have a modern compiler which supports std::thread, you can use that instead of pthreads and have the code much simpler - you just need to create a std::function object and pass it to std::thread's constructor.

Upvotes: 2

Elemental
Elemental

Reputation: 7521

You simple can't do what you are trying to do - a member function (UNLESS it is static) needs an object in which to be called - that is the process starting the thread can't just call MyClass::f() because it needs to call something.f() - and it doesn;t know what something is.

Typically one gets around this by defining a static member function which takes the object as a parameter and then calls the member function on that object.

Upvotes: 1

Related Questions