Function pointer as a member of a class - c++

What's the difference between a class function and global function with regard to function pointers in C++? I'm asking as the Windows CreateThread method doesn't seem to accept the function that the thread code goes in if the function is a class member.
I can pass the function (that the thread code goes in) to the CreateThread message when it is a global method, but once I make it a member of a class I get the error "argument of type [method layout] is incompatible with parameter of type LPTHREAD_START_ROUTINE". ClassName::* is in the middle now; is this affecting it?
What is the way around this?

Member function pointers (DWORD(WINAPI Foo::*)(LPVOID)) are different types than function pointers (DWORD(WINAPI *)(LPVOID)). Member functions have a hidden this parameter, causing a signature mismatch.
The easiest way to do this is to use C++11's <thread> header:
struct Foo {
void threadProc() {}
};
int main() {
Foo foo;
std::thread t{&Foo::threadProc, foo, /*other arguments to threadProc*/};
t.join();
}
If you have to resort to CreateThread, make use of the void * parameter to pass the instance:
struct Foo {
DWORD threadProc() {...}
};
extern "C" DWORD WINAPI proxyThreadProc(LPVOID userData) {
auto foo = static_cast<Foo *>(userData);
if (foo) {foo->threadProc();}
}
int main() {
Foo foo;
CreateThread(..., proxyThreadProc, &foo, ...);
}
The one in your class can now be pretty much whatever you want (like a std::function) and still work, as long as it's called with the right arguments from within the proxy procedure.

yeah, as #chris said there is a hidden pointer of this which will be connected by the end of parameters. when the thread carry out that, it don't know to match with a pointer in the position of the last parameter, then it failed to recover the heap of this function when finished, so It's banned to use non-static member function of class to drive a thread function except for the global function or static member function of class.

Related

Pass class function to another class function

sorry for possible duplicates, but I didn't understand the examples and codes snippets I found.
I have a class named "EncoderWrapper" which includes some functions. One of these functions is called "onAfterTouch" and is declared in the "EncoderWrapper.h" file.
void onAfterTouch(byte channel, byte pressure);
The functions will become a callback for another class function of a library I use
inline void setHandleAfterTouch(void (*fptr)(uint8_t channel, uint8_t pressure)) {
usb_midi_handleAfterTouch = fptr;
};
Note: I'm totally new to C++, so I want to say sorry if I'm doing some "no-gos" or mixing up some terms.
The question is: How can I pass my class function (member function?) to that "setHandleAfterTouch" function of the library?
This won't work:
void EncoderWrapper::attachMIDIEvents()
{
usbMIDI.setHandleAfterTouch(&EncoderWrapper::onAfterTouch);
}
... my IDE says
no matching function for call usb_midi_class:setHandleAfterTouch(void (EncoderWrapper::*)(byte, byte))
I've also tried
usbMIDI.setHandleAfterTouch((&this->onAfterTouch));
But this won't work ... and I don't get the approach on that.
Every Help is very appreciated ;-)
Function pointer and member function pointer have different types. You can it for yourself:
struct Test {
void fun();
};
int main() {
void(*ptr)() = &Test::fun; // error!
}
Instead, member function pointer need this syntax:
void(Test::*fun)() = &Test::fun; // works!
Why you ask? Because member function need an instance to be called with. And calling that function have a special syntax too:
Test t;
(t.*funptr)();
To accept member function pointer, you'll need to change your code to this:
inline void setHandleAfterTouch(void(EncodeWrapper::*fptr)(uint8_t, uint8_t)) {
usb_midi_handleAfterTouch = fptr;
};
Since it's rather limiting accepting only the functions from one class, I recommend using std::function:
inline void setHandleAfterTouch(std::function<void(uint8_t, uint8_t)> fptr) {
usb_midi_handleAfterTouch = std::move(fptr);
};
This will allow you to send lambda with captures, and call your member function insode it:
// we capture this to use member function inside
// v---
usbMIDI.setHandleAfterTouch([this](uint8_t, channel, uint8_t pressure) {
onAfterTouch(channel, pressure);
});
It seems you can't change, and by looking quickly at the API, it doesn't seem you have access to a state object.
In that case, if you want to use your member function, you need to introduce a global state:
// global variable
EncodeWrapper* encode = nullptr;
// in your function that sets the handle
encode = this; // v--- No capture makes it convertible to a function pointer
usbMIDI.setHandleAfterTouch([](uint8_t, channel, uint8_t pressure) {
encode->onAfterTouch(channel, pressure);
});
Another solution would be to make onAfterTouch function static. If it's static, it's pointer is not a member function pointer, but a normal function pointer.

Is there a way to pass a member function to pthread_cleanup_push?

I want to know the way to pass a member function to pthread_clean_push. I don't want to declare the cleanup function as static and pass object's reference to it. Below is the scenario
class Foo{
public:
Foo(string name):name(name){};
void setBar1(){bar1=malloc(4);sleep(20);};
void setBar2(){bar2=malloc(10);sleep(50);};
void cleanBar1(void* arg){free(bar1);};
void cleanBar2(void* arg){free(bar2);};
private:
string name;
void* bar1;
void* bar2;
};
void* myPThread(void* arg){
Foo theFoo(*(string*)(arg));
theFoo.setBar1();
pthread_cleanup_push(&theFoo.cleanBar1,NULL); //what is the correct way to
theFoo.setBar2();
pthread_cleanup_push(&theFoo.cleanBar2,NULL); //pass clean functions?
sleep(100);
pthread_cleanup_pop(1);
pthread_cleanup_pop(1);
return NULL;
}
int main(){
string biryani="biryani";
string pappu="pappu";
pthread_t makeBirayani, makePappu;
pthread_create(&makeBiryani,NULL,&myPThread,(void*)&biryani);
pthread_create(&makePappu,NULL,&myPThread,(void*)&pappu);
pthread_join(makeBiryani,NULL);
pthread_join(makePappu,NULL);
return 0;
}
I avoided compile-time error ISO C++ forbids taking the address of a bound member function to form a pointer to member function by using (void(*)(void*))&Foo::cleanBar1 as the argument to pthread_cleanup_push(). But run-time error(segmentation fault) occurs with multiple threads as it has ambiguity in determining the instance to which the cleanup function belongs. How to invoke the member function like here in this scenario? What is the syntax?
Foo::cleanBar1 and Foo::cleanBar2 are non-static member functions, which means that they take an implicit first argument, a pointer to the Foo instance on which they must be invoked (the this pointer). So you cannot pass a pointer to member function to pthread_cleanup_push and get the desired behavior.
You'll need to create a dispatcher function that calls the member function you want, and then pass a pointer to that function to pthread_cleanup_push. This dispatch function could either be a free function, or a static member function of Foo. For instance,
class Foo{
public:
Foo(string name):name(name){}
void setBar1(){bar1=malloc(4);sleep(20);}
void cleanBar1(){free(bar1);}
static void bar1_callback(void *arg)
{
static_cast<Foo*>(arg)->cleanBar1();
}
// ..
private:
string name;
void* bar1;
void* bar2;
};
And then pass it to pthread_cleanup_push as
pthread_cleanup_push(&Foo::bar1_callback, &theFoo);
Now the call to pthread_cleanup_pop will execute Foo::bar1_callback and pass it a pointer to the theFoo instance, which will then invoke the cleanBar1() member function.
The member function needs to know the object for which it is executed. This is why the standard doesn't allow this direct reference.
Just use a lambda-wrapper, like:
pthread_cleanup_push( [](void*a)->void { reinterpret_cast<Foo*>(a)->cleanBar1(NULL);},
&theFoo); //&theFoo will be passed as argument to the function
However you MUST ensure that your theFoo object still exist when the cleanup is called, because you give its adress when you push the cleanup function, and this address will later be used as argument for the cleanup by the lambda function.
From my understanding of the pthread function pthread_cleanup_push function you can pass the address of a free function (or possibly static to the class Foo) to it and a pointer to an object and then route the call to the correct member.
void clean_bar_1(void* arg)
{
Foo* p = static_cast<Foo*>(arg);
p->cleanBar1();
}
And then in myPThread function:
pthread_cleanup_push(&clean_bar_1, &theFoo);
And repeat for the cleanBar2 method.

Error while calling function from pthread_create()

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.

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
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.

C++ Thread in member function

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.