Reputation: 241
I have the following class:
class Foo {
private:
Bar *_bar;
void *run(void *);
public:
Foo(Bar *bar);
}
I want Foo::Foo
to launch a thread running Foo::run
.
I know this can be done using std::thread
:
Foo::Foo(Bar *bar) : _bar(bar) {
_thread = std::thread(&Foo::run, this);
}
The problem is I need to set a priority and a scheduling policy for this thread - which can be achieved using pthread
.
(very) sadly, I cannot change the design of the system and I have to spawn the thread inside of the C'tor.
pthread
is a C API and I can't figure out how to run it on a nonstatic member function. The following attempts did not compile:
Foo::Foo*(Bar *bar) : _bar(bar) {
// attempt 1
pthread_create(&thread, NULL, &Foo::run, this);
// attempt 2
pthread_create(&thread, NULL, (void* (*)(void *))(&Foo::run), this);
}
From the pthread_create
man page - the third argument (start_routine
) is a pointer to a function returning void *
and receiving void *
.
Upvotes: 0
Views: 817
Reputation: 4314
The calling conventions for C and C++ are totally different because a C++ function (unless static) needs to know which instance of a class to call its member function with.
What you can do is have a static function and the incoming parameter is the instance pointer. Like this:
class Foo
{
private:
Bar *_bar;
static void *start_thread(void *ptr) { return dynamic_cast<MyThread *>(ptr)->run(); }
void *run(); // Implement thread here.
public:
Foo(Bar *bar);
}
Foo::Foo(Bar *bar) : _bar(bar) {
pthread_create(&thread, NULL, Foo::start_thread, this);
}
Upvotes: 1
Reputation: 170123
Member functions aren't like free functions. They need an instance of the class to be invocable. As such, the type system treats them differently and pointers to member functions are not like regular pointers to free functions. std::thread
uses templates to present a convenience API that can accept either.
Naturally, pthreads aren't templated, and don't account for anything that isn't a free function. To make it run a member function on an object, you need a trampoline function. A function that can decay to a free function pointer, and contains code to execute your member on the instance you pass as void.
If you find yourself needing those often, you can write a template that will generate them for you. Like so:
template<class C, void* (C::* run_mem)()> // Member function without argumnets
void* pthread_member_wrapper(void* data) {
C* obj = static_cast<C*>(data)
return (obj->*run_mem)();
}
So if you define run
as void *run();
, you can use the above wrapper anywhere run
is accessible:
Foo::Foo*(Bar *bar) : _bar(bar) {
pthread_create(&thread, NULL,
pthread_member_wrapper<Foo, &Foo::run>,
this);
}
Since pthread_member_wrapper
is templatized on a class and member function pointer, you can reuse it with any class, in any scope where that member is accessible. It doesn't have to be a member of Foo
itself.
Upvotes: 0