How to pass a class-member function to pthread_create(....)?

H

Huskier

Hi all:

I want to pass a class-member function to pthread_create, and my
code is in the following, but I don't know how to pass
myobj.thread_function to pthread_create function.

#include <pthread.h>
class test
{
public:
test(){}
~test(){}
void thread_function(void*){}

};

int main()
{
test myobj;

pthread_t thrd;

pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

/**************************************************************/
/* How to pass myobj.thread_function(NULL) to pthread_create(...)*/
pthread_create(&thrd, &attr, /*????????*/, NULL);
/**************************************************************/

pthread_attr_destroy(&attr);

}

the pthread_create(...)'s Syntax

#include <pthread.h>;

int pthread_create (pthread_t *thread, const pthread_attr_t *attr, void
*(*start_routine) (void *), void *arg) ;
 
M

Maxim Yegorushkin

Hi all:

I want to pass a class-member function to pthread_create, and my
code is in the following, but I don't know how to pass
myobj.thread_function to pthread_create function.

[]

See, pthread_create() takes a callback function pointer and a user void*
pointer which can be used for passing a pointer to an object. All you have
to do is to use little thunk as a thread start routine that directs the
control flow into a member function of the object.

#include <pthread.h>

class test
{
public:
test(){}
~test(){}
void thread_function(){}

};

template<class T, void(T::*mem_fn)()>
void* thunk(void* p)
{
(static_cast<T*>(p)->*mem_fn)();
return 0;
}

int main()
{
test myobj;

pthread_t thrd;

pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

pthread_create(&thrd, &attr, thunk<test, &test::thread_function>,
&myobj);

pthread_attr_destroy(&attr);
}
 
I

Ian

Hi all:

I want to pass a class-member function to pthread_create, and my
code is in the following, but I don't know how to pass
myobj.thread_function to pthread_create function.
You absolutely can't!

A C++ member function is not an extern "C" function as required for
pthread_create.

It my have different linkage and it also has a hidden this parameter, so
the signature is wrong.

Some environments will let you get away with a static member, but this
isn't portable.

Your best bet is to have the method to be called public and pass an
instance of the class as the arg parameter. The start_routine can then
cast it's parameter and call the member.

Don't forget to declare the start_routine as extern "C".

Ian
 
I

Ian

Maxim said:
Hi all:

I want to pass a class-member function to pthread_create, and my
code is in the following, but I don't know how to pass
myobj.thread_function to pthread_create function.


[]

See, pthread_create() takes a callback function pointer and a user
void* pointer which can be used for passing a pointer to an object. All
you have to do is to use little thunk as a thread start routine that
directs the control flow into a member function of the object.

#include <pthread.h>

class test
{
public:
test(){}
~test(){}
void thread_function(){}

};

template<class T, void(T::*mem_fn)()>
void* thunk(void* p)
{
(static_cast<T*>(p)->*mem_fn)();
return 0;
}
But a template can't be extern "C", as required by pthread_create.

Ian
 
M

Maxim Yegorushkin

[]
But a template can't be extern "C", as required by pthread_create.

That is true. In theory.

Could you please name the environment where this does not
compile/link/work?
 
I

Ian

Maxim said:
[]
But a template can't be extern "C", as required by pthread_create.


That is true. In theory.

Could you please name the environment where this does not
compile/link/work?
Sun CC gives a warning, but still works. I assume any reasonably
compliant compiler will issue a warning.

Ian
 
R

redrocknomad

Hi all:

I want to pass a class-member function to pthread_create, and my
code is in the following, but I don't know how to pass
myobj.thread_function to pthread_create function.

#include <pthread.h>
class test
{
public:
test(){}
~test(){}
void thread_function(void*){}

};

int main()
{
test myobj;

pthread_t thrd;

pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

/**************************************************************/
/* How to pass myobj.thread_function(NULL) to pthread_create(...)*/
pthread_create(&thrd, &attr, /*????????*/, NULL);
/**************************************************************/

pthread_attr_destroy(&attr);

}

the pthread_create(...)'s Syntax

#include <pthread.h>;

int pthread_create (pthread_t *thread, const pthread_attr_t *attr, void
*(*start_routine) (void *), void *arg) ;

Perhaps this is not the most elegant solution, but I worked around this
by using a friend function along the lines of:

friend void* tfunc(void* args);

I then passed this friend function to the pthread_create(...) function,
casted the args value to my class name:

void* tfunc(void* args)
{
test* threadClass = (test*)args;
test->thread_function(0);
return 0;
}

This solutions doesn't let you pass along the void* args parameters,
but you can get around this by adding a member in your class that
stores the void* args to be retrieved once the thread is executed.

You then move thread_function() to be protected and have a
ThreadStart(void* args) or something along those lines that is called
to launch the thread.

-Collin
 
?

=?iso-8859-1?q?Stephan_Br=F6nnimann?=

IIRC the DEC CXX compiler required the declaration of
the thread function before it was declared friend
in the Thread class: making the function static
in the class itself did not help.

Stephan
 
V

verec

I want to pass a class-member function to pthread_create ...

One key may be to not mix abstractions and not abuse inheritance.

A Thread class should really be some kind of "helper" that allows
you to execute _some code_ that is unrelated to the thread class
by itself, but is only required to run in some specific OS provided
thread of execution (irrespective of your Thread class)

In the simplest case, when you do want to abuse inheritance:

struct thread {
// stuff ommitted
virtual void
start() {
int code = ::pthread_create(
&handle
, &(attributes->get())
, pthread_main
, reinterpret_cast<void *>(this)) ;

if (code) throw int_exception(code) ;
}

// stuff ommitted
virtual void
run() {
}

// stuff ommitted
static void *
pthread_main(void * a) {
thread * t = reinterpret_cast<thread *>(a) ;
if (t) {
t->run() ;
}
return a ;
}
} ;

Now, if you do want to have your "runnables" and your thread class
be independent concepts & citizens, I 'd suggest you have a look
at this (still in progress) piece of work:

http://wiki.uiwithstyle.org/wiki.pl?Minimal_Object_Model
 
I

Ian

verec said:
// stuff ommitted
static void *
pthread_main(void * a) {

Why do people keep using static members here when this is plain wrong?
Don't the compiler warnings tell you something?

Ian
 
I

Ian

verec said:
Could you elaborate?
pthread_create is a C function. The third parameter is

void* (*start_routine)(void*)

So when called from C++, this function has the signature

extern "C" void* (*start_routine)(void*)

Which doesn't match a static class member function.
No. gcc 4.0, -Wall
Well it should!

Ian
 
V

verec

pthread_create is a C function. The third parameter is

void* (*start_routine)(void*)

So when called from C++, this function has the signature

extern "C" void* (*start_routine)(void*)

Which doesn't match a static class member function.

Hmmm. The only thing that would disqualify the static member
in this case is that its linkake is not declared ``extern "C"''.

But if we get down to the spirit of this linkage/ABI requirements
(as opposed to its strict letter), this static member function:
- takes a C style argument (a void *, that cannot be any of the
the more esoteric C++ types (references or polymorphic types)
- returns a C style argument (ditto)

So the only contention point might now reside with name mangling,
and indeed the mom::thread::pthread_main static member appears
as:

__ZN3mom6thread12pthread_mainEPv

I just don't see any _requirement_ in pthread (or anywhere else
for that matter!) that would restrict the kind of name that
a function, (extern "C" or otherwise) must have in order for
the actual link (and further down the road: loading & resolving)
to succeed, provided such a name is what common linkers/loaders
do expect.

Precisely, this whole name mangling business has been invented
by Stroustrup to make sure that linkers/loaders would unwittingly
cooperate.

I would tend to see this whole argument as wrong headed nit-picking,
until proven wrong by an actual refence to the relevant paragraph(s)
of the ISO-C++ document.

Beside this, exiting _practice_ has been using this idiom as far
back as C++ existed, precisely to help map OS defined callbacks
to the "object world of C++". I've been using this since around 1989
(Yep, I'm _that_ old :)
Well it should!

Again: please quote the standard refence paragraph, and I'm sure
that the GCC developers will be more than willing to adapt.

(And I will be very sorry and will have to go through more convoluted
routes to achieve what is a basically a pointer to standard C function!)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top