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 *.
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);
}
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.
Related
I have declared a function in the Class definition inside a header file:
class A
{
public:
...
void* func(void *);
...
}
In a .C file, I've a pointer to the class A's object as ptr.
Now, when i create a pthread:
iret1 = pthread_create(&thread1, NULL, ptr->func, NULL);
It throws an error as:
error: a pointer to a bound function may only be used to call the function.
But when I declare the function func as static, this error doesn't come.
I just want to know a workaround for this as I can't change the function to static since I can't call other non-static members from it.
You can't use non-static member functions as thread functions, or as functions to any non-C++ function expecting a function pointer. The reason is that all non-static member function has a hidden first argument that becomes the this pointer.
In this case it can be solved with a static proxy-function:
class A
{
public:
void* func();
static void* wrapper(void* object)
{ return reinterpret_cast<A*>(object)->func(); }
};
...
A* ptr = new A;
iret1 = pthread_create(&thread1, NULL, &A::wrapper, ptr);
This will create the thread with A::wrapper as the thread function, and pass the instance pointer as argument. The A::wrapper function then uses this argument as a pointer to the instance, and calls the real function.
However, if you have a C++11 capable compiler and standard library, there are much better support for threads:
A myA;
std::thread myThread(&A::func, &myA);
The above object creation creates a thread that will call A::func and pass the hidden first argument to the function as it needs.
I have a question related with C++ and threads.
I am more familiar with Java than C++ and this error is confusing me.
Imagine that in x.h file I have a class such as:
class A{
public A();
public virtual void* func(void*);
public virtual void func2();
public virtual void func3();
};
In x.cpp file I want to do that:
void* A::func(void*) {
while(....)
func2();
return NULL;
}
void A::func2() {
...some stuff there...
}
void A::func3() {
pthread_t t1;
pthread_create(&t1, NULL, &A::func, NULL);
void* result;
pthread_join(t1,&result);
...some other stuff...
}
The problem is it hangs with the following error:
"error: ISO C++ forbids taking the address of an unqualified or
parenthesized non-static member function to form a pointer to member
function."
What should I do to fix this?
Thanks.
This is a lousy error message, but fundamentally what it's trying to tell you is that you can't form a function pointer from an instance method (I'm not sure what Java's terminology here is). This is because to call an instance method you need both the address of the actual code and the address of an object to be this, and a regular function pointer only stores the former.
What you need here is a static wrapper method which matches pthread_create's expectations of the thread start routine. You pass this as the fourth argument to pthread_create, and the wrapper converts its argument back to an object pointer and invokes func. This type of wrapper is commonly known as a "thunk", since it adapts one calling convention to another.
class A {
// ...
static void* thread_start_thunk(void* self);
};
void*
A::thread_start_thunk(void* self)
{
return static_cast<A*>(self)->func();
}
// ...
void
A::func3()
{
// ....
pthread_create(&t1, 0, &A::thread_start_thunk, static_cast<void*>(this));
// ...
}
The casts are unavoidable.
You can not just pass a pointer to a method to the thread. That method-pointer alone would not mean anything, because it does not know which instance it belongs to. If you need to call an instance method in a different thread, add a private static method to the class and pass it's address to the thread, along with a pointer to the instance as an argument.
That static method could look somewhat like this:
class A
{
public: virtual void threadMethod();
public:
static void staticThreadMethod(void* instanceObj)
{
((A*)instanceObj)->threadMethod();
}
};
I did not test that code and it obviously does not check for errors, but this is how I usually do it.
use one of:
boost::thread
C++11
some other C++ library threads (a plenty of them)
add a static method to your class, then pass its address to pthread_create w/ user provided void* to pair of your class instance (pointer/ref) and class::*method you want to call. then in static function just call desired method using instance and method address obtained from parameter
In pthread_create(&t1, NULL, &func, NULL); you try to take the address of a member function. There are two issues with that
The correct form is
&A::func
this is what the compiler tries to tell you.
pthread_create wants a pointer to function, not a pointer to a non-static member function. What you can do instead is, creating a static member function and passing the address of this static member function as an argument to pthread_create.
Example:
class A {
public:
static void *func(void *);
};
pthread_t t1;
pthread_create(&t1, NULL, &A::func, NULL);
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
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);
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.
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.
can I use thread in member function to call a member function for C++ in windows? If yes, how to implement it? Here is the sample
void Class::fun_1(void){
_beginthread(fun_2, 0, NULL); //This is the error line :: function call missing argument list; use '&Class::fun_2' to create a pointer to member
}
void Class::fun_2(void){
printf("hello");
}
Thanks
There are actually multiple issues here:
You can't pass a pointer to a member function as the routine to the _beginthread() function. The function requires a pointer to a global or static function.
Standard C++ requires that you fully qualify the member function name (even within the class) and use an & to obtain a pointer to the member (the compiler was complaining to you about this point).
Because you can't pass a member function pointer to _beginthread(), you need to create a wrapper global or static function to make it work. Here's one way to make that happen:
class MyClass
{
public:
void fun_1()
{
_beginthread(&MyClass::fun_2_wrapper, 0, static_cast<void*>(this));
}
private:
void fun_2()
{
printf("hello");
}
static void __cdecl fun_2_wrapper(void* o)
{
static_cast<MyClass*>(o)->fun_2();
}
};
Of course, you need to somehow guarantee that the MyClass object will still exist for as long as fun_2() is running, or not-so-good things will happen. If you much rather not have to worry about it, consider using Boost.Thread which does basically this and much more for you.
The usual way to do this is to use a static member function that calls the member function using a void pointer to the original object.
class Class
{
public:
void fun_1(void)
{
_beginthread( &Class::static_fun_2, 0, this );
}
void fun_2(void)
{
printf("hello");
}
private:
static void static_fun_2( void * args )
{
static_cast<Class*>(args)->fun_2();
}
};
However if you start needing to pass arguments to those functions things get a little more complicated. I'd look at using boost::thread and boost::bind instead of rolling your own.
As the title says.
The following is my code skeleton.
class CLASS
{
public:
void A();
private:
DWORD WINAPI B(LPVOID);
};
void CLASS::A()
{
DWORD (WINAPI CLASS::*thread)(LPVOID) = &CLASS::B;
...
CreateThread(NULL, 0, thread, &arg, 0, NULL);
...
}
the function B needs CLASS's member variables.
But I've got an error code when I compiled this.
It's " can't convert argument 3 from 'DWORD (__stdcall CLASS::* )(LPVOID)' to 'LPTHREAD_START_ROUTINE' " or something like that.
I don't know if it is the same in the english environment.
can anybody help please?
Seriously, use std::thread:
class CLASS
{
public:
void A();
private:
void B(your args go here);
};
void CLASS::A()
{
std::thread t(&CLASS::B, this, your args go here);
// when done
t.join();
// or
t.detach();
}
Explanation
Your code doesn't compile because CreateThread is a C API, expecting a non-member C function as a callback. In order to call a non-static member function of a C++ class, the caller needs to know about this pointer and how to correctly use it. Since WinAPI clearly doesn't have this and doesn't expect a member function pointer, this cannot possibly work. Your compiler catches this and reports it as a type mismatch error.
This is where the lpParameter of CreateThread comes into play. It allows you to pass this through that parameter. However it doesn't change the fact that CreateThread doesn't know how to call C++ member functions. Therefore it's your responsibility to wrap it in a static function that will do the member function call:
class CLASS
{
public:
void A();
private:
DWORD B();
static DWORD s_B(LPVOID);
};
DWORD CLASS::s_B(LPVOID that) {
return ((CLASS*)that)->B();
}
void CLASS::A() {
CreateThread(NULL, 0, s_B, this, 0, NULL);
}
This is what #Nawaz does in their answer, except in a slightly more general way.
Even though this approach works, it clearly has downsides:
It's verbose.
It's non portable.
You need to pass your original args through different means (e.g. through a member of your class).
std::thread already does all that for you.
You've to define your callback function as static function if it's member function!
Better design : define a reusable class!
From my previous answer: (with little modification)
Even better would be to define a reusable class with pure virtual function run() to be implemented by the derived thread classes. Here is how it should be designed:
//runnable is reusable class. All thread classes must derive from it!
class runnable
{
public:
virtual ~runnable() {}
static DWORD WINAPI run_thread(LPVOID args)
{
runnable *prunnable = static_cast<runnable*>(args);
return prunnable->run();
}
protected:
virtual DWORD run() = 0; //derived class must implement this!
};
class Thread : public runnable //derived from runnable!
{
public:
void newthread()
{
CreateThread(NULL, 0, &runnable::run_thread, this, 0, NULL);
}
protected:
DWORD run() //implementing the virtual function!
{
/*.....your thread execution code.....*/
}
}
You have to make that member function static.
The problem here is that every non-static member function has an implicit this parameter and that's in fact what the compiler is trying to tell you - your nin-static member function has signature different from the one you expected.
Also see this answer to a closely related question.