By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,098 Members | 1,893 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,098 IT Pros & Developers. It's quick & easy.

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

P: n/a
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) ;

Jul 23 '05 #1
Share this Question
Share on Google+
12 Replies


P: n/a
On Fri, 15 Jul 2005 12:07:19 +0400, <Hu*****@gmail.com> wrote:
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);
}

--
Maxim Yegorushkin
<fi****************@gmail.com>
Jul 23 '05 #2

P: n/a
Ian
Hu*****@gmail.com wrote:
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

Jul 23 '05 #3

P: n/a
Ian
Maxim Yegorushkin wrote:
On Fri, 15 Jul 2005 12:07:19 +0400, <Hu*****@gmail.com> wrote:
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
Jul 23 '05 #4

P: n/a
On Fri, 15 Jul 2005 13:37:18 +0400, Ian <no***@nowhere.com> wrote:

[]
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?

--
Maxim Yegorushkin
<fi****************@gmail.com>
Jul 23 '05 #5

P: n/a
Ian
Maxim Yegorushkin wrote:
On Fri, 15 Jul 2005 13:37:18 +0400, Ian <no***@nowhere.com> wrote:

[]
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
Jul 23 '05 #6

P: n/a


Hu*****@gmail.com wrote:
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

Jul 23 '05 #7

P: n/a
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

Jul 23 '05 #8

P: n/a
On 2005-07-15 09:07:19 +0100, Hu*****@gmail.com said:
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?...l_Object_Model

--
Do your users a favor: give them Style: http://www.uiwithstyle.org

Jul 23 '05 #9

P: n/a
Ian
verec wrote:

// 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
Jul 23 '05 #10

P: n/a
On 2005-07-17 03:39:19 +0100, Ian <no***@nowhere.com> said:
Why do people keep using static members here when this is plain wrong?
Could you elaborate?
Don't the compiler warnings tell you something?


No. gcc 4.0, -Wall

--
JFB

Jul 23 '05 #11

P: n/a
Ian
verec wrote:
On 2005-07-17 03:39:19 +0100, Ian <no***@nowhere.com> said:
Why do people keep using static members here when this is plain wrong?

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.
Don't the compiler warnings tell you something?

No. gcc 4.0, -Wall

Well it should!

Ian
Jul 23 '05 #12

P: n/a
On 2005-07-17 05:35:48 +0100, Ian <no***@nowhere.com> said:
verec wrote:
On 2005-07-17 03:39:19 +0100, Ian <no***@nowhere.com> said:
Why do people keep using static members here when this is plain wrong?

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.


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 :)
Don't the compiler warnings tell you something?

No. gcc 4.0, -Wall

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!)
--
JFB

Jul 23 '05 #13

This discussion thread is closed

Replies have been disabled for this discussion.