Solved

Creating a thread with non-static function

Posted on 1998-08-11
14
275 Views
Last Modified: 2012-05-04
I'am trying to create a worker thread to perform some tasks. When the
code is in C++, the entry function of the thread must be static,
otherwise I get compilation errors.

This doesn't work:

class myclass{
        void primary(void);
        DWORD secondary(LPVOID pParam);
};

void myclass::primary(void) {
        // do something

        AfxBeginThread(secondary, NULL);

        // do something
}

DWORD myclass::secondary(LPVOID pParam) {
        // do something
}
       
compiler error: error C2665: 'AfxBeginThread' : none of the 2 overloads
can convert parameter 1 from type 'unsigned int (void *)'

But if I do:

class myclass{
        void primary(void);
        static DWORD secondary(LPVOID pParam);
}

its ok.

this is also ok:

class myclass{
        void primary(void);
}

// not a classc member
DWORD secondary(LPVOID pParam) {
        // do something
}


First "solution" forces me to declare as static all member
variables/functions this function access/call, and to be allowed to run
just one instance of thbis function. That is for sure not what I want.

Second "solution" leaves me out of the class object, and i don't want
that too.

Any hint?

Thanks in advance,

0
Comment
Question by:careton
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
14 Comments
 
LVL 22

Expert Comment

by:nietod
ID: 1169938
answer coming.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1169939
First of all--the problem.
The function

       DWORD secondary(LPVOID pParam);

is not the same as the function

       DWORD myclass::secondary(LPVOID pParam);

that is because the first function takes one parameter, pParam, and the other function takes two.  The additional parameter is a pointer to the object that the function is called for.  The famous "this" pointer.  This is a parameter to the function, but one that you don't have to declare.  So the two functions aren't the same that is why you had the compiler error.  Now if you declare myclass::secondary to be static, then it is not called for an object, then it doesn't have the "hidden" this pointer parameter.  That is why it compiles with it declared as static.

continues
0
 
LVL 22

Expert Comment

by:nietod
ID: 1169940
The way around this is to use an "interface" function.  This is a static function, that is called with a pointer to an object in its parameters (not a hidden pointer like, "this").  It then uses the pointer to call the non-static function, like

class myclass{
           void primary(void);
           static DWORD interface(LPVOID pParam);
           DWORD secondary();
   };

   void myclass::primary(void)
  {
           AfxBeginThread(interface,this); // call inteface passing pointer to this object.
   }

   DWORD myclass::interface(LPVOID pParam)
   {
      myclass *ObjPtr = (myclass *) pParam;  // Convert parameter to -> object.
      ObjPtr->secondary();
   }

   DWORD myclass::secondary()
   {
   }

notice that secondary() is not called with parameters this way.  That is because the parameter passed to the thread was a pointer to the object.  If you need to pass a parameter to secondary() that can be arranaged with a small extension to this design.
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:careton
ID: 1169941
Nietod:
I don't understand: if it as you say, any call to a member function should generate an error because of missing "this" parametes. In any case, how do you suggest to make the call?
0
 
LVL 22

Expert Comment

by:nietod
ID: 1169942
As I said:  "This is a parameter to the function, but one that you don't have to declare"

a non-staticmember function works on a object, right.  It must know what object to work on as there are possibly many objects.  The only way it can know what object to work on is if it gets a parameter that indicates what object.  To make your life easier this parameter is "hidden" from you.  You don't have to specify it when you call the procedure and you don't have to specify it when it when you declare the procedure.  But the parameter is actually there.  (It may be passed by a different mechansim than other parameters however.)  

Since the compiler knows about this hidden parameter it "sees" a difference between a non-static member procedure and a regular procedure.  Thus it doesn't allow you to use them interchangably.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1169943
>> how do you suggest to make the call

Like I did in the above sample.  The AfxBeginThread() function must call a "regular" function.  That is, one that doesn't have a "this" passed.  so you give it one, a static member function.  I called it interface().  But I passed a pointer to an object as a ordinary (not hidden) parameter to this procedure.  I then use that pointer to call a member function of that pointer's class.  

Take a look at the code again.
0
 

Author Comment

by:careton
ID: 1169944
I think there is some missunderstanding: when the compiler sends the error
compiler error: error C2665: 'AfxBeginThread' : none of the 2 overloads
    can convert parameter 1 from type 'unsigned int (void *)'

it means to the 2 overloads of AfxBeginThread, not about "secondary" function. In my code I have just one "secondary" function, the one that is member of the class (and I want it to be non-static) and is called from within "primary" function, which is also member of the class. So "this" pointer will point to the same myclass object, and there should be no confusions.

Any call like this works fine. Just AfxBeginThread causes this problem.
Am I missing something?

0
 
LVL 22

Expert Comment

by:nietod
ID: 1169945
Forget the solution for the moment.  Just try to understand the problem.

Look at the following.  I declare 4 functions.  Two of them can be called by AfxBeginThread() and two of them cannot.

class myclass
{
           DWORD willnotwork1(LPVOID pParam);
           static DWORD willwork1(LPVOID pParam);
};

DWORD willwork2(LPVOID pParam);
static DWORD willnotwork2(myclass *This,LPVOID pParam);

 AfxBeginThread(myclass::willnotwork1, NULL);  // doesn't work takes an extra hidden parameter.

 AfxBeginThread(myclass::willwork1, NULL);  // does work, static, doesn't take an extra hidden parameter.

 AfxBeginThread(willwork2, NULL);  // does work, not a member, doesn't take an  object pointer.

 AfxBeginThread(willnotwork2, NULL);  // doesn't work, takes an extra, non-hidden parameter..

for a function to be called by AfxBeginThread it must take one parameter of type void.  If it takes a second parameter, hidden or not, it won't work and the compiler willl detect this.

Does that help?
0
 
LVL 6

Expert Comment

by:snoegler
ID: 1169946
nietod is absolutely right ...
At machine language level a call to a member function of a class takes an extra argument:
Assume the function:
void myclass::test(int number)
{
}

If you call this function for example by  pMyClass->test(5) it is called as if it would look like this:
void myclass::test(myclass* this, int number)
{
 ...
}

And any member variable you access within this function, like
 my_member_variable=number; // my_member_variable is a member of myclass
gets converted to:
 this->my_member_variable=number;

So this 'this' pointer which gets passed without being visible in the source code will ALWAYS
miss because the AfxBeginThread function WILL NOT pass it. The only way is to pass the
'this' pointer as the real, visible extra argument ...
0
 
LVL 22

Expert Comment

by:nietod
ID: 1169947
Thanks, snoegler.

careton,

You said "it means to the 2 overloads of AfxBeginThread, not about "secondary" function"
The reason it is complaing about overloads for AfxBeginThread() is that it thinks you are trying to call a 3rd overload for the function, one that takes a pointer to a member procedure of the MyClass class.  Thus, it is looking at the type of the first parameter and seens that it doesn't match the type of any of its overloads.

It you can understand that, I will try again to explain how to make this work.
0
 
LVL 3

Expert Comment

by:xyu
ID: 1169948
a. Go to: http://www.geocities.com/SiliconValley/1741/
b. Register and Download the Natlib Template Library
c. open zip file
d. look at
      natlib\include\nwthread.h
      natlib\src\nwthread.cpp
   for TWin32Thread the class that is similar to one You writing (meanwile this implementation is very close to Borland's TThread one)

0
 

Author Comment

by:careton
ID: 1169949
Ok! now I get it. Sorry it took so much clarifications.
Nietod, how do I grade now your answer? It appears as rejected, and its locked by "xyu" (thanks to you too, but nietod "worked" much harder on this)
0
 
LVL 22

Accepted Solution

by:
nietod earned 100 total points
ID: 1169950
Thanks.

You undersand the problem--do you understand the solution as well?
0
 

Author Comment

by:careton
ID: 1169951
Oh yes! you know, understanding the problem is 'almost' solving it.
Thanks,
careton
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

728 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question