c++ thread issue - c++

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.

Related

Creating a pthread of nonstatic member function

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.

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.

How can I pass method pointer as a function parameter in C++ while using pthreads

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);

How can I fix the error in this Pthread example?

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.