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.
Related
I created a library in which one exposed function accepts a function pointer of type void(*fun_ptr)(int).
The function syntax is:
start_server(char *devices, char *folder, int number, int timeout, void(*status_of_server)(int));
This is working with normal C++ functions like void getStatus(int n); but when I used them in a Visual C++ environment for a GUI application, I'm getting this error:
A pointer to member is not valid for a managed class
start_server(&devs, &base, 1, 0, &TestApplication::MainWindow::StatusOfServer );
Where StatusOfServer is defined inside the MainWindow class which can be used for UI management.
private: void TestApplication::MainWindow::StatusOfServer(int n)
{
this->progressBar->Value = n;
}
What is the correct way of handling this?
The reason for the weird behavior is that each member function has implicitly appended to it's signature a pointer to it's type, e.g. :
#include <iostream>
struct S
{
int i;
void doSth() { std::cout << i << std::endl; }
};
int main()
{
S s{1};
s.doSth();
auto member_f = &S::doSth;
(s.*member_f)();
}
doSth() has a hidden parameter, so it can't be called like a regular function. In your example the situation is similar- you are trying to call member function as if it was a normal free function, which will not work. Usually in APIs requesting function pointers, the functions can take void* as parameter, which allows you to write a wrapper that will cast the pointer to the correct type and then invoke member function on the pointed to instance of the class. However from the code you've shown above, you can't pass void* into the function, so you'll have probably have some sort of global state (e.g. make that function static and let it work only on static data).
One solution would be to create a small non-managed wrapper function around the managed one:
void wrapStatusOfServer(int n) {
TestApplication::MainWindow::StatusOfServer(n)
}
and get a pointer to the wrapper
start_server(&devs, &base, 1, 0, &wrapStatusOfServer);
Another solution: turn your start_server into managed code and use a delegate instead of a function pointer: https://learn.microsoft.com/en-us/cpp/dotnet/how-to-define-and-use-delegates-cpp-cli?view=vs-2017
C++/CLI is fraught with this kind of issue, where managed and un-managed code and data are almost but not quite interoperable.
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.
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 have 2 classes
class B {
public:
int func(int i);
};
class A {
public:
typedef int (B::*fPtr)(int);
void run();
B* mB;
};
void A::run() {
// create a pointer
fPtr p = &(B::func);
// invoke the function
mB->*p(2); <------- Compilation Error
}
What i need is to create a pointer to func() in A's run function. I get a compilation error saying that mB is not corresponding to a function with 1 argument.
please help
You need to put parentheses around the function expression:
(mB->*p)(2);
But as others have pointed out, there's almost certainly a better way to do what you're trying to do.
Instance methods on a class always have a hidden first parameter for the this pointer, thus it is incompatible with your function pointer typedef. There is no way directly to obtain a pointer to a member function. The typical workaround is to use a "thunk" where you pass a static function that accepts a generic "catch all" parameter (such as void *) which can be statically cast to a pointer of your choosing on which you can invoke the member function. Example:
class B
{
public:
static void MyThunk(void * obj)
{
static_cast<B *>(obj)->MyRealFunc();
}
void MyRealFunc()
{
// do something here
}
// . . .
};
You can get a pointer to the static function easily as it has no 'hidden this', just reference it using B::MyThunk. If your function requires additional parameters, you can use something like a functor to capture the necesssary parameters and state.
You should definitely read this C++ FAQ Lite page which tells you much more about all this: Pointers to member functions
why can you not call mB->func(2);?
If you need different functions for B perhaps look into virtual functions and class inheritance
I did all the necessary configurations, like including Pthread library and header files...
The error is:
error C3867: 'FunctionClass::calledfunction': function call missing argument list; use '&FunctionClass::calledfunction' to create a pointer to member
Here's the example that causes the error:
class FunctionClass
{
public:
void * calledfunction( void *);
/*
this is the definition of the function in the FunctionClass.cpp
void * FunctionClass::calledfunction( void *)
{
//do sth;
}
*/
};
int main(void)
{
pthread_t process_m;
FunctionClass *obj = new FunctionClass ();
int nbr= 5;
if(pthread_create(&process_m,NULL,obj->calledfunction,(void *)nbr)< 0)
{
std::cout << "thread1";
}
}
What could cause the error? I respected the syntax of the function pthread_create... But I can't find the reason for this error!
You cannot use non-static member functions as callback.
Use a free function or a static member function as third parameter of pthread_create.
Edit to reflect OP's comment:
If you need to call a function member of FunctionClass for a specific FunctionClass object (obj in your example) the common way is that of calling a static member function (or a free one) passing your object to it, and then call object's member function from there.
Here an example (didn't test it, but it should let you understand what to do):
struct obj_arg_pair { FunctionClass *obj; int nbr; };
static void * calledfunctionStatic( void *args_ )
{
obj_arg_pair *args = reinterpret_cast< obj_arg_pair * >( args_ );
return args->obj->calledFunction( args->nbr );
}
and then start your thread with a code similar to this one:
obj_arg_pair args;
args.nbr = 5;
args.obj = obj;
pthread_create(&process_m,NULL,FunctionClass::calledfunction,(void *)&args);
calledfunction must be static or non class function.
Edit:
If you need to call nonstatic function do following.
struct forFunctionCalling
{
FunctionClass * ptr;
void * otherarguments;
};
void * somefunction (void * v)
{
forFunctionCalling * f_ptr = reinterpret_cast<forFunctionCalling>(v);
return f_ptr->ptr->calledfunction(f_ptr->otherarguments);
}
And call somefunction instead calledfunction.
P.S. Of course this code will look much better if you change type otherarguments from void * to it's real type
You need to do as the others here have suggested: create an "object" to hold all the data your function needs then pack that into the "void *" parameter. The function should be a free-function or a static class member function - the static member function if it needs access to private members of the class.
What I will add is how you must handle the lifetime of the objects you pack into your "void *" holder. You can:
use "new" to create it. You will know then it exists but must delete it at some point. You cannot pass shared_ptr to your thread-function but you can put shared_ptr in your thread-function itself if you know it was created for you with "new". You could also make the deleter one of the members of the packed struct, and use that in boost::shared_ptr so at call time you indicate how to clean up the data.
use wait mechanisms so the caller waits for the thread to "accept" the data before exiting where the objects will lose scope. The thread "accepts" after making copies of this data for its use. That way you can create a local struct of the data and pass that in.
You might consider using boost::thread although where you can pass in shared_ptr objects as parameters to boost::bind and write your function in a way to receive these.