Another thread as a member function thread 
Author Message
 Another thread as a member function thread

Hi,

I've been following several threads from people trying to figure out how to
make a thread a member function of another class.  Me too.

The MS documentation is quite specific on worker threads. The thread
prototype should look like:

INT MyControllingFunction( LPVOID pParam );

and the thread should be started like this:

NewObject = new CMyObject;
AfxBeginThread(MyThreadProc, pNewObject);

That does works, but the started thread doesn't have access to the member
of the class that started it.  You can make it a member function of the
starting class by moving the prototype to the class definitions and change
the way it's started somewhat:

UINT (MyClass::*pmfnMyThread)() = &MyClass::MyThread;
AfxBeginThread(*(AFX_THREADPROC*)&pmfnMyThread, this);

That also works, but the started thread doesn't have unreferenced access to
the starting classes member without the use of the passed "this" typecast
to a pointer.   In other words, the thread has to use pClass->m_member
rather than just m_member.  

If you check the value of "this" in the started thread, it's garbage.  That
explains why just m_member references won't work.  So, you must use the
passed AfxBeginThread PVOID parameter to pass "this" to the started thread.

Someone else suggested that this form would be better:

UINT __stdcall MyThread();

UINT (_stdcall MyClass::*pmfnMyThread)() = &MyClass::MyThread;
AfxBeginThread(*(AFX_THREADPROC*)&pmfnMyThread, this);

And indeed it is.  The "this" pointer in the started thread is now valid
and so references to the members of the starting class now work.   However,
the price is the changing of the calling convention which has an
unfortunate side effect.  It's  no longer possible to use the
AfxBeginThread PVOID pParm to pass information to the started thread.  If
you change the above to include the usual "pParam" value, the thread
receives garbage in that parameter.  "this" now works, but "pParam"
doesn't.

So, the choices seem to be:

1) No "this" pointer but a valid param which can be used to pass "this".
Access to members is only through the passed pParam value.

2) No pParam value but a valid "this" which can be used to directly access
the starting class members.  This is definitely the easiest, unless you
absolutely need to pass some kind of other information to the started
thread.

So the question is, does anyone know how to get a valid "this" AND "param"
in the started thread?  I have a multi-instance thread, in which I would
like to direct access to the class members, but each instance of the thread
needs to receive different starting information.  The threads overlap
execution, so short of some sort complicated thread startup handshaking and
parameter passing, I can't figure out how to get the best of both worlds, a
valid "this" and a valid "pParam".

Any ideas?  Thanks much,

Bruce A. Chastain



Mon, 12 Jul 1999 03:00:00 GMT  
 Another thread as a member function thread

Bruce,

Here is how to make a member function of your class run in a separate
thread:

The answer is to use a static member function, but make it a dispatcher of
sorts.

The LPVOID parameter that you pass to to the static function can be
anything  Why not pass in a pointer to simple structure (allocated on the
HEAP, not the stack) that contains all the data you need.  Define the
structure however you want.  You can put a *this* pointer in there as well
as any data you want.

The static function can then extract from that structure a pointer to the
object, member function, and any other data needed:  For example, suppose
you wanted to call a member function of your CMyObject class which required
an integer and a CString for arguments, and returned a BOOL value.  Your
code might look something like this:

// -----------------------------------------------------------------
// STEP 1: -- define needed items
// -----------------------------------------------------------------
// Define a "MEMPTR" as a pointer to a member function
// of a CMyObject object which takes an integer and an
// LPCTSTR as arguments and returns a BOOL

typedef BOOL (CMyObject::*MEMPTR)(int, LPCTSTR);

// Define a structure (MYSTRUCT) that will hold all the
// information to be passed to the static thread procedure.

typedef struct
{
     CMyObject* pObj;         // point to the object
     MEMPTR             pFunction; // points to object's member func
     int                        nArg1;       // first argument
     CString                    strArg2;     // second argument

Quote:
}  MYTHREADSTRUCT;

//
----------------------------------------------------------------------------
------
// STEP 2:  Define static function that will serve as our thread proc
// all this function will do is call the proper object's member function
// with the values passed in.
//
----------------------------------------------------------------------------
------

INT MyThreadFunction(LPVOID pParam)
{
     MYSTRUCT* pStruct = (MYSTRUCT*)pParam;

     // Extract elements of the structure (to make the code readable)

     CMyObject* pObj = pStruct->pObj;
     MEMPTR pFunction = pStruct->pFunction;
     int nArg1 = pStruct->nArg1;
     CString strArg2 = pStruct->strArg2;

      // Call the member function of pObj, passing the arguments;

     BOOL bStat = (pObj->*pFunction)(nArg1, strArg2);

     // if ( !bStat )
     {
          TRACE("Function failed!");
     }

     // Don't forget to delete the structure

     delete pStruct;

Quote:
}

//
----------------------------------------------------------------------------
--
// STEP 3: -- define the CMyObject threaded member function
//
----------------------------------------------------------------------------
--
// Here is the CMyObject member function which will
// run in its own thread

BOOL CMyObject::ThreadedFunction(int nArg1, LPCTSTR strArg2)
{
     // All of the code here runs in another thread.  Fill this in with
     // whatever you want your threaded member function to do.

    return TRUE; // must return some BOOL value

Quote:
}

// ---------------------------------------------------
// STEP 4: -- start the thread somewhere
// ---------------------------------------------------
// FINALLY, how do we begin this thread?  Here's how to start it from
within
// another member function of the CMyObject class

void CMyObject::StartTheThread(int nArg1, CString strArg2)
{
     // Whip up a MYSTRUCT structure and fill it with all of the
     // information that our static function needs.

     MYSTRUCT* pStruct = new MYSTRUCT;
     pStruct->pObj = this;
     pStruct->pFunction = &CMyObject::ThreadedFunction;
     pStruct->nArg1 = nArg1;
     pStruct->strArg2 = strArg2;

     // Start the thread.  Note that "MyThreadFunction" is responsible for
     // deleting the MYSTRUCT structure we created.

     AfxBeginThread(MyThreadFunction, (LPVOID)pStruct);

Quote:
}

This is admittedly a bit crude from an object-oriented point of view, but
it illustrates the point.

I hope this helps you.  If you are interested, e-mail me back and I can
show you a cleaner (and cooler) way to to this with templates.

Joe O'



Quote:
> Hi,

> I've been following several threads from people trying to figure out how
to
> make a thread a member function of another class.  Me too.

> The MS documentation is quite specific on worker threads. The thread
> prototype should look like:

> INT MyControllingFunction( LPVOID pParam );

> and the thread should be started like this:

> NewObject = new CMyObject;
> AfxBeginThread(MyThreadProc, pNewObject);

> That does works, but the started thread doesn't have access to the member
> of the class that started it.  You can make it a member function of the
> starting class by moving the prototype to the class definitions and
change
> the way it's started somewhat:

> UINT (MyClass::*pmfnMyThread)() = &MyClass::MyThread;
> AfxBeginThread(*(AFX_THREADPROC*)&pmfnMyThread, this);

> That also works, but the started thread doesn't have unreferenced access
to
> the starting classes member without the use of the passed "this" typecast
> to a pointer.   In other words, the thread has to use pClass->m_member
> rather than just m_member.  

> If you check the value of "this" in the started thread, it's garbage.
That
> explains why just m_member references won't work.  So, you must use the
> passed AfxBeginThread PVOID parameter to pass "this" to the started
thread.

> Someone else suggested that this form would be better:

> UINT __stdcall MyThread();

> UINT (_stdcall MyClass::*pmfnMyThread)() = &MyClass::MyThread;
> AfxBeginThread(*(AFX_THREADPROC*)&pmfnMyThread, this);

> And indeed it is.  The "this" pointer in the started thread is now valid
> and so references to the members of the starting class now work.  
However,
> the price is the changing of the calling convention which has an
> unfortunate side effect.  It's  no longer possible to use the
> AfxBeginThread PVOID pParm to pass information to the started thread.  If
> you change the above to include the usual "pParam" value, the thread
> receives garbage in that parameter.  "this" now works, but "pParam"
> doesn't.

> So, the choices seem to be:

> 1) No "this" pointer but a valid param which can be used to pass "this".
> Access to members is only through the passed pParam value.

> 2) No pParam value but a valid "this" which can be used to directly
access
> the starting class members.  This is definitely the easiest, unless you
> absolutely need to pass some kind of other information to the started
> thread.

> So the question is, does anyone know how to get a valid "this" AND
"param"
> in the started thread?  I have a multi-instance thread, in which I would
> like to direct access to the class members, but each instance of the
thread
> needs to receive different starting information.  The threads overlap
> execution, so short of some sort complicated thread startup handshaking
and
> parameter passing, I can't figure out how to get the best of both worlds,
a
> valid "this" and a valid "pParam".

> Any ideas?  Thanks much,

> Bruce A. Chastain




Wed, 14 Jul 1999 03:00:00 GMT  
 Another thread as a member function thread

Justin,

I did some reading on TLS and I don't understand how it would help.  It
appears that any TLS declared variable is local to one thread instance, and
so by definition, can't be accessed by any other thread.

Since my goal is to have a valid "this" which prevents me from using the
AfxBeginThread() PVOID parameter, I assume you meant the use of TLS to
replace the usual PVOID param, and I don't see how a TLS declared variable
would help.  Whatever TLS declared variable accessed by the startING
thread, would be local to that thread, and so never seen by the startED
thread.

Thanks for the help,
Bruce A. Chastain



Quote:
> Check out Thread Locale Storage, or TLS.  It will allow you to pass
> data into a thread.

> Justin



Thu, 15 Jul 1999 03:00:00 GMT  
 Another thread as a member function thread

Joseph,

Yes, making the thread a static function and passing a pointer to a
structure of thread instance data is the usual way, but I'm trying to make
the thread a member function of a class.  That way, you don't need the
pStruct-> on all the references.  If the class and thread are large, and
the threead has lots of subroutines, the readability difference can be
substantial, not to mentioned the reduction in typing.

My goal is to have a thread as a member function that has direct access to
the class member variables, without the use of additional structures,
pointers, parameter copying, etc., just like any other member function of
the same class.

As I noted in my message, I have the "this" part working which eliminates
the need to pass it as a parameter, but the price is the loss of the PVOID
param value.

Thanks for the help,
Bruce A. Chastain



Quote:
> Bruce,

> Here is how to make a member function of your class run in a separate
> thread:

> The answer is to use a static member function, but make it a dispatcher
of
> sorts.

> The LPVOID parameter that you pass to to the static function can be
> anything  Why not pass in a pointer to simple structure (allocated on the
> HEAP, not the stack) that contains all the data you need.  Define the
> structure however you want.  You can put a *this* pointer in there as
well
> as any data you want.

> ..........

> Joe O'



Thu, 15 Jul 1999 03:00:00 GMT  
 Another thread as a member function thread


Quote:
>Joseph,

>Yes, making the thread a static function and passing a pointer to a
>structure of thread instance data is the usual way, but I'm trying to make
>the thread a member function of a class.  That way, you don't need the
>pStruct-> on all the references.  If the class and thread are large, and
>the threead has lots of subroutines, the readability difference can be
>substantial, not to mentioned the reduction in typing.

PMFJI, but Joseph described how to do just that. To summarize:

1. You specify a non-member or static member function for your
threadproc, as is required, passing it a pointer to a structure
containing a pointer to the object you want to control the thread;
2. From the threadproc, you call some member function through the
object, with whatever arguments you like, which are usually contained
in the structure you passed to the threadproc via the CreateThread
function.

Quote:
>My goal is to have a thread as a member function that has direct access to
>the class member variables, without the use of additional structures,
>pointers, parameter copying, etc., just like any other member function of
>the same class.

Starting a thread requires a pointer to a non-member or static member
function; a non-static member function simply won't do.

Quote:
>As I noted in my message, I have the "this" part working which eliminates
>the need to pass it as a parameter, but the price is the loss of the PVOID
>param value.

In your other message, you were doing things like:

Quote:
> UINT __stdcall MyThread();

> UINT (_stdcall MyClass::*pmfnMyThread)() = &MyClass::MyThread;
> AfxBeginThread(*(AFX_THREADPROC*)&pmfnMyThread, this);

If the above works, it's purely accidental, and at best, very brittle.
That code makes a number of assumptions concerning things that aren't
guaranteed. Try Joseph's method. It will work, and it's legal C++.

--
Doug Harrison



Fri, 16 Jul 1999 03:00:00 GMT  
 Another thread as a member function thread

Hi,

I've been following several threads from people trying to figure out how to
make a thread a member function of another class.  Me too.

The MS documentation is quite specific on worker threads. The thread
prototype should look like:

INT MyControllingFunction( LPVOID pParam );

and the thread should be started like this:

NewObject = new CMyObject;
AfxBeginThread(MyThreadProc, pNewObject);

That does works, but the started thread doesn't have access to the member
of the class that started it.  You can make it a member function of the
starting class by moving the prototype to the class definitions and change
the way it's started somewhat:

UINT (MyClass::*pmfnMyThread)() = &MyClass::MyThread;
AfxBeginThread(*(AFX_THREADPROC*)&pmfnMyThread, this);

That also works, but the started thread doesn't have unreferenced access to
the starting classes member without the use of the passed "this" typecast
to a pointer.   In other words, the thread has to use pClass->m_member
rather than just m_member.  

If you check the value of "this" in the started thread, it's garbage.  That
explains why just m_member references won't work.  So, you must use the
passed AfxBeginThread PVOID parameter to pass "this" to the started thread.

Someone else suggested that this form would be better:

UINT __stdcall MyThread(void);

UINT (_stdcall MyClass::*pmfnMyThread)(void) = &MyClass::MyThread;
AfxBeginThread(*(AFX_THREADPROC*)&pmfnMyThread, this);

And indeed it is.  The "this" pointer in the started thread is now valid
and so references to the members of the starting class now work.   However,
the price is the changing of the calling convention which has an
unfortunate side effect.  It's  no longer possible to use the
AfxBeginThread PVOID pParm to pass information to the started thread.  If
you change the above to include the usual "pParam" value, the thread
receives garbage in that parameter.  "this" now works, but "pParam"
doesn't.

So, the choices seem to be:

1) No "this" pointer but a valid param which can be used to pass "this".
Access to members is only through the passed pParam value.

2) No pParam value but a valid "this" which can be used to directly access
the starting class members.  This is definitely the easiest, unless you
absolutely need to pass some kind of other information to the started
thread.

So the question is, does anyone know how to get a valid "this" AND "param"
in the started thread?  I have a multi-instance thread, in which I would
like to direct access to the class members, but each instance of the thread
needs to receive different starting information.  The threads overlap
execution, so short of some sort complicated thread startup handshaking and
parameter passing, I can't figure out how to get the best of both worlds, a
valid "this" and a valid "pParam".

Any ideas?  Thanks much,

Bruce A. Chastain



Fri, 16 Jul 1999 03:00:00 GMT  
 Another thread as a member function thread

I didn't get all of the message but from what I have read, you are trying
to simplify thread creation with classes.  Here is my technique.

////////////////////////////////////////////////////////////////////////////
///////////////
class MyClass
{
virtual void DoWork();
static void ThreadFunc(CMyClass* p);

Quote:
};

void CMyClass::TheadFunc(CMyClass* p)
{
    p->DoWork();

Quote:
}

void CMyClass::DoWork()
{
  // do whatever you want in the background thread
Quote:
}

////////////////////////////////////////////////////////////////////////////
/////////////////

This allows you to call AfxBeginThread( CMyClass::ThreadFunc, <Instance of
CMyClass> );

Hope this helps.

--
Ben Strum
Sun Investors Co., Inc.



Quote:

> >Joseph,

> >Yes, making the thread a static function and passing a pointer to a
> >structure of thread instance data is the usual way, but I'm trying to
make
> >the thread a member function of a class.  That way, you don't need the
> >pStruct-> on all the references.  If the class and thread are large, and
> >the threead has lots of subroutines, the readability difference can be
> >substantial, not to mentioned the reduction in typing.

> PMFJI, but Joseph described how to do just that. To summarize:

> 1. You specify a non-member or static member function for your
> threadproc, as is required, passing it a pointer to a structure
> containing a pointer to the object you want to control the thread;
> 2. From the threadproc, you call some member function through the
> object, with whatever arguments you like, which are usually contained
> in the structure you passed to the threadproc via the CreateThread
> function.

> >My goal is to have a thread as a member function that has direct access
to
> >the class member variables, without the use of additional structures,
> >pointers, parameter copying, etc., just like any other member function
of
> >the same class.

> Starting a thread requires a pointer to a non-member or static member
> function; a non-static member function simply won't do.

> >As I noted in my message, I have the "this" part working which
eliminates
> >the need to pass it as a parameter, but the price is the loss of the
PVOID
> >param value.

> In your other message, you were doing things like:

> > UINT __stdcall MyThread();

> > UINT (_stdcall MyClass::*pmfnMyThread)() = &MyClass::MyThread;
> > AfxBeginThread(*(AFX_THREADPROC*)&pmfnMyThread, this);

> If the above works, it's purely accidental, and at best, very brittle.
> That code makes a number of assumptions concerning things that aren't
> guaranteed. Try Joseph's method. It will work, and it's legal C++.

> --
> Doug Harrison




Sat, 17 Jul 1999 03:00:00 GMT  
 Another thread as a member function thread

Quote:
> So the question is, does anyone know how to get a valid "this" AND
"param"
> in the started thread?  I have a multi-instance thread, in which I would
> like to direct access to the class members, but each instance of the
thread
> needs to receive different starting information.  The threads overlap
> execution, so short of some sort complicated thread startup handshaking
and
> parameter passing, I can't figure out how to get the best of both worlds,
a
> valid "this" and a valid "pParam".

> Any ideas?  Thanks much,

Easy: put the this pointer in the structure that you pass via pParam.

But wait, lets look into the other type of thread.  Those derived from
CWinThread!

later,
Jim



Sun, 18 Jul 1999 03:00:00 GMT  
 Another thread as a member function thread

Doug,

Quote:
> PMFJI, but Joseph described how to do just that. To summarize:

>  You specify a non-member or static member function for your
> threadproc, as is required, passing it a pointer to a structure
> containing a pointer to the object you want to control the thread;
> 2. From the threadproc, you call some member function through the
> object, with whatever arguments you like, which are usually contained
> in the structure you passed to the threadproc via the CreateThread
> function

Yes, Joseph has been helping me via email and finally cracked through the
wall which was keeping me from understanding how starting a static function
could preserve "this".  His sample code finally switched on the light for
me.  Thanks very much for your help!

Bruce A. Chastain



Sun, 18 Jul 1999 03:00:00 GMT  
 Another thread as a member function thread


Quote:
>Yes, Joseph has been helping me via email and finally cracked through the
>wall which was keeping me from understanding how starting a static function
>could preserve "this".  His sample code finally switched on the light for
>me.  Thanks very much for your help!

Glad you got it working. This is probably obvious, but you also have
to pay close attention to the lifetime of the object serving as the
thread argument. When passing a pointer for the thread argument, you
have to ensure the pointed-to thing and its sub-objects exist as long
as the thread uses them. Joseph accomplished this by passing a pointer
to a new'd object, which the thread has to delete, and that object
contained no sub-objects (e.g. pointers to other objects) that could
go out of scope in the caller thread, except for the CMyObject
pointer, which presumably isn't a problem. Again, it's probably
obvious, but it's still easy to get wrong.

--
Doug Harrison



Sun, 18 Jul 1999 03:00:00 GMT  
 Another thread as a member function thread

Doug,

Yep, I knew I was going to have to clean the passed object, buuuuut I had
forgotten about it until your very well timed reminder. <g>

I've been struggling with the "right" way to do threads over the last
several weeks and I feel *much* better about my approach now.

Thanks again for the help!

Bruce Chastain



Quote:

> >Yes, Joseph has been helping me via email and finally cracked through
the
> >wall which was keeping me from understanding how starting a static
function
> >could preserve "this".  His sample code finally switched on the light
for
> >me.  Thanks very much for your help!

> Glad you got it working. This is probably obvious, but you also have
> to pay close attention to the lifetime of the object serving as the
> thread argument. When passing a pointer for the thread argument, you
> have to ensure the pointed-to thing and its sub-objects exist as long
> as the thread uses them. Joseph accomplished this by passing a pointer
> to a new'd object, which the thread has to delete, and that object
> contained no sub-objects (e.g. pointers to other objects) that could
> go out of scope in the caller thread, except for the CMyObject
> pointer, which presumably isn't a problem. Again, it's probably
> obvious, but it's still easy to get wrong.

> --
> Doug Harrison




Sun, 18 Jul 1999 03:00:00 GMT  
 
 [ 11 post ] 

 Relevant Pages 

1. Using class member function as a thread function

2. Using class member function as a thread function

3. Visual C++ - Threads and Member Functions

4. member function as thread??

5. Starting a thread which is a member function of a class

6. Q: Member function - Worker thread - MFC

7. Member function - Worker thread - MFC

8. Calling class member functions from a new thread

9. Launching multiple threads using member functions

10. Accessing member variables in a thread function...

11. Starting up a thread of a member function of a C++ class

12. Threaded function mangles CString members?

 

 
Powered by phpBB® Forum Software