Solved

Creating a thread with non-static function

Posted on 1998-08-11
14
260 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
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
 

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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
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

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

Often, when implementing a feature, you won't know how certain events should be handled at the point where they occur and you'd rather defer to the user of your function or class. For example, a XML parser will extract a tag from the source code, wh…
Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
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.

706 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

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now