public inbox for pthreads-win32@sourceware.org
 help / color / mirror / Atom feed
* RE: Using a class method as starting routine.
@ 2001-08-01  1:39 Gardian, Milan
  0 siblings, 0 replies; 6+ messages in thread
From: Gardian, Milan @ 2001-08-01  1:39 UTC (permalink / raw)
  To: Ye Liu, pthreads-win32, pthreads-win32-info

Hi Ye, pthread gurus,


> A rather dump question: how to use a class method as a 
> starting routine of pthread_create().

I agree with what John Bossom already wrote -> the Java-like approach is
simple and powerful. First, you should create a new abstract class that will
take care of the nasty details of delegation (alias proxying), e.g.:

//runnable.h
//----------
#include <assert.h>
#include <pthread.h>
extern "C" void *runnable_exec_redirector(void *arg);
class Runnable
{
    //Public interface
    public:
        bool start_thread();
        bool join_thread(void ** ret_value = 0);

        Runnable() : _id_valid(false) {};
        virtual ~Runnable() { assert( !_id_valid ); };


    //Methods that must be overriden in a subclass
    protected:
        virtual void *run() = 0;

        //allow this function to access class details and run method
        friend void *runnable_exec_redirector(void *arg);


    //Attributes, available to subclasses
    protected:
        bool      _id_valid;
        pthread_t _thread_id;
};
//----------(eof)


//runnable.cpp
//----------
#include "runnable.h"
bool Runnable::start_thread()
{
    if (!_id_valid) {
        if (0 == pthread_create(
          &_thread_id, 0,
          runnable_exec_redirector,
          static_cast<void *>(this)
        )) {
            _id_valid = true;
        }
    }
    return _id_valid;
}

bool Runnable::join_thread(void ** ret_value)
{
    bool ret = false;
    if (_id_valid) {
        pthread_join(_thread_id, ret_value);
        _id_valid = false;
        ret = true;
    }
    return ret;
}

extern "C" void *runnable_exec_redirector(void *arg)
{
    assert (arg != 0);
    Runnable *obj = static_cast<Runnable *>(arg);
    assert (obj != 0);
    return obj ? obj->run() : 0;
}
//----------(eof)




You can now reuse this code in as many thread classes as you want (of course
you can refine the above code to support re-entrancy and zillion other
features, this is just a skeleton). Let's take a look at an example:


//test.cpp
//----------
#include <iostream>
#include "runnable.h"
class MyThread : public Runnable
{
    private:
        virtual void *run()
        {
            std::cout
                << "I am thread " << _thread_id
                << " running in context of object " << this
                << std::endl;
            return 0;
        }
};

int main()
{
    MyThread t;
    std::cout << "Thread object " << &t << std::endl;

    t.start_thread();
    t.join_thread();

    return 0;
}
//----------(eof)


As you can see, all you have to do in your "thread" class (MyThread in the
example above) is to (usually publicly) derive from "Runnable" -> i.e. make
your class runnable ;). This gives your class instant access to the Runnable
public methods (start_thread, join_thread and whatever you can think of).

The only other think you need to do is to define & implement the 'run' pure
virtual method (otherwise you would not be able to create instances of your
class :) ). You can think of the 'run' method as the starting routine for
the created thread, and it is instance method, not a static method (and
that's what you wanted).

Of course, your question was how to use instance method DIRECTLY in
pthread_create -> it is NOT possible (search through history of
news://comp.programming.threads for detailed explanation). But this simple
'proxy' strategy is at least as good as the direct usage (in my opinion even
better).

If you have any further questions/problems, let me know.

Hope this helps,

	Milan.

PS: The above code was successfully tried in "VC++6, SP4" (alias "Microsoft
(R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804") and "gcc version
2.95.3-5 (cygwin special)".

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Using a class method as starting routine.
  2001-07-30 20:06 ` Wayne Isaacs
@ 2001-07-31 12:09   ` Ye Liu
  0 siblings, 0 replies; 6+ messages in thread
From: Ye Liu @ 2001-07-31 12:09 UTC (permalink / raw)
  To: Wayne Isaacs, pthreads-win32, pthreads-win32-info

Thanks, Wayne.

I found my problem later after I posted the mail. Now my class is like:

/*    create.h    */
#ifndef _CREATE_H_
#define _CREATE_H_

#include <stdio.h>
#include "pthread.h"

class create
{
public:
 create();
 static void *thread_routine(void *arg)
{
    create *pObject = (create *)pObject;
    ...
}
 void start();
};

#endif

/*    create.cpp    */
#include "create.h"

void *create::thread_routine(void *arg)
{
 printf("The thread is here\n");
 return NULL;
}

void create::start()
{
 pthread_t thread_id;
 pthread_attr_t thread_attr;

 pthread_create(&thread_id, &thread_attr, create::thread_routine, (void *)this);

}

Pass this as the arg to the thread routine to enable it to access the
members/methods of the class: static function can only access the static
members/methods of the class. I feel it is an even better way in sense of Object
Oriented.

--ye


Wayne Isaacs wrote:

> I have never found a way to generate a usable function pointer from a
> non-static class method.  It may be theoretically incorrect to even try,
> because a non-static class method should not exist independently from the
> data object.
>
> On the other hand, if you declare the method 'static', then that method
> exists independent of data.  The compiler will let you generate and use a
> pointer to any static method.
>
> I would be interested to know Bjarne Stroustrup's preference on this issue,
> because the static function pointer required to launch thread routines is
> contrary to object orientation, but a fact of life for the major operating
> systems.
>
> I have written several thread classes.  Usually, the class object carries a
> thread function pointer and a termination event in private data.  The class
> defines the thread function pointer as a typedef.  The thread function takes
> two parameters; a void pointer for data, and an event pointer for
> termination.  That way, when the thread class object goes out of scope and
> destructs, it can gracefully terminate the thread.
>
> something like:
>
> class ThreadFn {
>
>     pthread_t thread_id;
>     HANDLE termination_event;
>
>     public:
>         typedef  long (*static_f_type)( HANDLE, void* );
>         ThreadFn( static_f_type );
>
>     };
>
> Wayne
>
> ----- Original Message -----
> From: "Ye Liu" <yliu@tibco.com>
> To: <pthreads-win32@sourceware.cygnus.com>;
> <pthreads-win32-info@sourceware.cygnus.com>
> Sent: Monday, July 30, 2001 4:46 PM
> Subject: Using a class method as starting routine.
>
> > Greets,
> >
> > A rather dump question: how to use a class method as a starting routine
> > of pthread_create().
> >
> > I have the following code:
> > /*    create.h    */
> > #ifndef _CREATE_H_
> > #define _CREATE_H_
> >
> > #include <stdio.h>
> > #include "pthread.h"
> >
> > class create
> > {
> > public:
> >  create();
> >  void *thread_routine(void *arg);
> >  void start();
> > };
> >
> > #endif
> >
> > /*    create.cpp    */
> > #include "create.h"
> >
> > void *create::thread_routine(void *arg)
> > {
> >  printf("The thread is here\n");
> >  return NULL;
> > }
> >
> > void create::start()
> > {
> >  pthread_t thread_id;
> >  pthread_attr_t thread_attr;
> >
> >  pthread_create(&thread_id, &thread_attr, create::thread_routine, NULL);
> >
> > }
> >
> > create::create()
> > {
> > }
> >
> > When I compiled it using VC6.0 (win32-pthread library of course), I got
> >
> > create.cpp
> > C:\ye\work\vs\pthread_projects\create\create.cpp(14) : error C2664:
> > 'pthread_create' : cannot convert parameter 3 from 'void *(void *)' to
> > 'void *(__cdecl *)(void *)'
> >         None of the functions with this name in scope match the target
> > type
> > Error executing cl.exe.
> >
> >
> > It seems that the compiler does not recognize thread_routine as a
> > address. Why does it happen? How to get around of it?
> >
> > Thanks a lot!
> >
> > --ye
> >
> >
> > --
> > Ye Liu
> > Tel(O) 650-846-5228
> >
> >

--
Ye Liu
Tel(O) 650-846-5228


^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: Using a class method as starting routine.
@ 2001-07-31  7:25 Bossom, John
  0 siblings, 0 replies; 6+ messages in thread
From: Bossom, John @ 2001-07-31  7:25 UTC (permalink / raw)
  To: 'Wayne Isaacs', Ye Liu, pthreads-win32, pthreads-win32-info

Instead of attempting to be able to call every method of a class as the
thread mainline, you could simply follow the JAVA thread model:
Designate the 'run' method as the starting point of your thread object.

Register a static method as the internal guts that passes the thread
class pointer as the sole parameter to the static method. Within the
static method, coerce the pointer back into the thread object and
call thread->run()

(I know... not the original problem, however, it keeps life simple.)



-----Original Message-----
From: Wayne Isaacs [ mailto:wisaacs@io.com ]
Sent: July 30, 2001 11:05 PM
To: Ye Liu; pthreads-win32@sourceware.cygnus.com;
pthreads-win32-info@sourceware.cygnus.com
Subject: Re: Using a class method as starting routine.


I have never found a way to generate a usable function pointer from a
non-static class method.  It may be theoretically incorrect to even try,
because a non-static class method should not exist independently from the
data object.

On the other hand, if you declare the method 'static', then that method
exists independent of data.  The compiler will let you generate and use a
pointer to any static method.

I would be interested to know Bjarne Stroustrup's preference on this issue,
because the static function pointer required to launch thread routines is
contrary to object orientation, but a fact of life for the major operating
systems.

I have written several thread classes.  Usually, the class object carries a
thread function pointer and a termination event in private data.  The class
defines the thread function pointer as a typedef.  The thread function takes
two parameters; a void pointer for data, and an event pointer for
termination.  That way, when the thread class object goes out of scope and
destructs, it can gracefully terminate the thread.

something like:

class ThreadFn {

    pthread_t thread_id;
    HANDLE termination_event;

    public:
        typedef  long (*static_f_type)( HANDLE, void* );
        ThreadFn( static_f_type );

    };


Wayne

----- Original Message -----
From: "Ye Liu" <yliu@tibco.com>
To: <pthreads-win32@sourceware.cygnus.com>;
<pthreads-win32-info@sourceware.cygnus.com>
Sent: Monday, July 30, 2001 4:46 PM
Subject: Using a class method as starting routine.


> Greets,
>
> A rather dump question: how to use a class method as a starting routine
> of pthread_create().
>
> I have the following code:
> /*    create.h    */
> #ifndef _CREATE_H_
> #define _CREATE_H_
>
> #include <stdio.h>
> #include "pthread.h"
>
> class create
> {
> public:
>  create();
>  void *thread_routine(void *arg);
>  void start();
> };
>
> #endif
>
> /*    create.cpp    */
> #include "create.h"
>
> void *create::thread_routine(void *arg)
> {
>  printf("The thread is here\n");
>  return NULL;
> }
>
> void create::start()
> {
>  pthread_t thread_id;
>  pthread_attr_t thread_attr;
>
>  pthread_create(&thread_id, &thread_attr, create::thread_routine, NULL);
>
> }
>
> create::create()
> {
> }
>
> When I compiled it using VC6.0 (win32-pthread library of course), I got
>
> create.cpp
> C:\ye\work\vs\pthread_projects\create\create.cpp(14) : error C2664:
> 'pthread_create' : cannot convert parameter 3 from 'void *(void *)' to
> 'void *(__cdecl *)(void *)'
>         None of the functions with this name in scope match the target
> type
> Error executing cl.exe.
>
>
> It seems that the compiler does not recognize thread_routine as a
> address. Why does it happen? How to get around of it?
>
> Thanks a lot!
>
> --ye
>
>
> --
> Ye Liu
> Tel(O) 650-846-5228
>
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Using a class method as starting routine.
  2001-07-30 13:50 Ye Liu
  2001-07-30 20:06 ` Wayne Isaacs
@ 2001-07-31  2:11 ` Ales Pour
  1 sibling, 0 replies; 6+ messages in thread
From: Ales Pour @ 2001-07-31  2:11 UTC (permalink / raw)
  To: Ye Liu; +Cc: pthreads-win32

Ye Liu wrote:
> A rather dump question: how to use a class method as a starting routine
> of pthread_create().

Most compilers will _let_ you use a STATIC method for thread starting
routine. If you are keen on portability, you will use an extern "C"
wrapper function.

Regards,
	Ales

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Using a class method as starting routine.
  2001-07-30 13:50 Ye Liu
@ 2001-07-30 20:06 ` Wayne Isaacs
  2001-07-31 12:09   ` Ye Liu
  2001-07-31  2:11 ` Ales Pour
  1 sibling, 1 reply; 6+ messages in thread
From: Wayne Isaacs @ 2001-07-30 20:06 UTC (permalink / raw)
  To: Ye Liu, pthreads-win32, pthreads-win32-info

I have never found a way to generate a usable function pointer from a
non-static class method.  It may be theoretically incorrect to even try,
because a non-static class method should not exist independently from the
data object.

On the other hand, if you declare the method 'static', then that method
exists independent of data.  The compiler will let you generate and use a
pointer to any static method.

I would be interested to know Bjarne Stroustrup's preference on this issue,
because the static function pointer required to launch thread routines is
contrary to object orientation, but a fact of life for the major operating
systems.

I have written several thread classes.  Usually, the class object carries a
thread function pointer and a termination event in private data.  The class
defines the thread function pointer as a typedef.  The thread function takes
two parameters; a void pointer for data, and an event pointer for
termination.  That way, when the thread class object goes out of scope and
destructs, it can gracefully terminate the thread.

something like:

class ThreadFn {

    pthread_t thread_id;
    HANDLE termination_event;

    public:
        typedef  long (*static_f_type)( HANDLE, void* );
        ThreadFn( static_f_type );

    };


Wayne

----- Original Message -----
From: "Ye Liu" <yliu@tibco.com>
To: <pthreads-win32@sourceware.cygnus.com>;
<pthreads-win32-info@sourceware.cygnus.com>
Sent: Monday, July 30, 2001 4:46 PM
Subject: Using a class method as starting routine.


> Greets,
>
> A rather dump question: how to use a class method as a starting routine
> of pthread_create().
>
> I have the following code:
> /*    create.h    */
> #ifndef _CREATE_H_
> #define _CREATE_H_
>
> #include <stdio.h>
> #include "pthread.h"
>
> class create
> {
> public:
>  create();
>  void *thread_routine(void *arg);
>  void start();
> };
>
> #endif
>
> /*    create.cpp    */
> #include "create.h"
>
> void *create::thread_routine(void *arg)
> {
>  printf("The thread is here\n");
>  return NULL;
> }
>
> void create::start()
> {
>  pthread_t thread_id;
>  pthread_attr_t thread_attr;
>
>  pthread_create(&thread_id, &thread_attr, create::thread_routine, NULL);
>
> }
>
> create::create()
> {
> }
>
> When I compiled it using VC6.0 (win32-pthread library of course), I got
>
> create.cpp
> C:\ye\work\vs\pthread_projects\create\create.cpp(14) : error C2664:
> 'pthread_create' : cannot convert parameter 3 from 'void *(void *)' to
> 'void *(__cdecl *)(void *)'
>         None of the functions with this name in scope match the target
> type
> Error executing cl.exe.
>
>
> It seems that the compiler does not recognize thread_routine as a
> address. Why does it happen? How to get around of it?
>
> Thanks a lot!
>
> --ye
>
>
> --
> Ye Liu
> Tel(O) 650-846-5228
>
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Using a class method as starting routine.
@ 2001-07-30 13:50 Ye Liu
  2001-07-30 20:06 ` Wayne Isaacs
  2001-07-31  2:11 ` Ales Pour
  0 siblings, 2 replies; 6+ messages in thread
From: Ye Liu @ 2001-07-30 13:50 UTC (permalink / raw)
  To: pthreads-win32, pthreads-win32-info

Greets,

A rather dump question: how to use a class method as a starting routine
of pthread_create().

I have the following code:
/*    create.h    */
#ifndef _CREATE_H_
#define _CREATE_H_

#include <stdio.h>
#include "pthread.h"

class create
{
public:
 create();
 void *thread_routine(void *arg);
 void start();
};

#endif

/*    create.cpp    */
#include "create.h"

void *create::thread_routine(void *arg)
{
 printf("The thread is here\n");
 return NULL;
}

void create::start()
{
 pthread_t thread_id;
 pthread_attr_t thread_attr;

 pthread_create(&thread_id, &thread_attr, create::thread_routine, NULL);

}

create::create()
{
}

When I compiled it using VC6.0 (win32-pthread library of course), I got

create.cpp
C:\ye\work\vs\pthread_projects\create\create.cpp(14) : error C2664:
'pthread_create' : cannot convert parameter 3 from 'void *(void *)' to
'void *(__cdecl *)(void *)'
        None of the functions with this name in scope match the target
type
Error executing cl.exe.


It seems that the compiler does not recognize thread_routine as a
address. Why does it happen? How to get around of it?

Thanks a lot!

--ye


--
Ye Liu
Tel(O) 650-846-5228


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2001-08-01  1:39 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-08-01  1:39 Using a class method as starting routine Gardian, Milan
  -- strict thread matches above, loose matches on Subject: below --
2001-07-31  7:25 Bossom, John
2001-07-30 13:50 Ye Liu
2001-07-30 20:06 ` Wayne Isaacs
2001-07-31 12:09   ` Ye Liu
2001-07-31  2:11 ` Ales Pour

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).