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

How to call static DWORD WINAPI ThreadFunc(LPVOID pvParam)

P: 52
I am facing a problem:

I have say 3 files :

ABC.h ----- this file has the function prototypes
ABC.cpp ------ the definitions of the functions
ABC_Test.cpp ------- the file with main() which calls the functions using ABC's object say "ob".


Now I want to make a function say "startNewThread()" inside ABC.cpp and its prototype in ABC.h, then where should I define

static DWORD WINAPI ThreadFunc(LPVOID pvParam);

function. Inside ABC_Test.cpp or inside ABC.cpp

Also Iwill call the createThread() of Win API inside startNewThread() and pass the ThreadFunc as one of its parameters. If this is possible, then its OK. But if I have to call some function of mine say

void ABC :: printXYZ() inside ThreadFunc , then how can I do this. I do not have my object say ABC ob; i.e. "ob" inside my ThreadFunc.

Please reply, if possible with a EXAMPLE code

Pawan
Feb 17 '07 #1
Share this Question
Share on Google+
6 Replies


Expert 100+
P: 1,510
not sure what the probelm is but you can call functions defined in your program from inside the threaded function. e.g.
Expand|Select|Wrap|Line Numbers
  1. #include <iostream>
  2. #include <windows.h>
  3. #include <process.h>
  4. using namespace std;
  5.  
  6. // function to print an int
  7. void myFunction(int i)
  8. {
  9.      cout << "This is prcosses number: " << i << "\n";
  10. }
  11.  
  12. // the thread function
  13. DWORD WINAPI ThreadProc(void *number)
  14. {    
  15.      int myNumber = *(int*)number;
  16.      myFunction(myNumber);
  17.      _endthread();
  18. }
  19.  
  20. // test from to call the thread function 10 times
  21. int main(int argc, char *argv[])
  22. {
  23.     int tempNum[10];
  24.     for( int i = 0; i <= 9; i++){
  25.          tempNum[i] = i;
  26.          HANDLE  handle = (HANDLE)CreateThread( NULL, 0, ThreadProc, (void*)&tempNum[i],0, NULL); // create thread
  27.         }  
  28.     system("PAUSE");
  29.     return 0;
  30. }
  31.  
Just be careful about accessing shared data structures etc
Feb 17 '07 #2

AdrianH
Expert 100+
P: 1,251
Expand|Select|Wrap|Line Numbers
  1.          HANDLE  handle = (HANDLE)CreateThread( NULL, 0, ThreadProc, (void*)&tempNum[i],0, NULL); // create thread
  2.  
What is important here is that you can pass a pointer. Oh, and that ThreadProc doesn't need to be called ThreadProc.

You can pass a pointer to an object if you like. Say you have a function DWORD fooThread(void * pObj), and an object fooObj of type foo. Then this becomes
Expand|Select|Wrap|Line Numbers
  1.          HANDLE  handle = (HANDLE)CreateThread(NULL, 0, fooThread, &fooObj, 0, NULL); // create thread
  2.  
and you function would be like so:
Expand|Select|Wrap|Line Numbers
  1. staic DWORD WINAPI fooThread(void* pObj)
  2. {
  3.   foo& rObj = *static_cast<foo*>(pObj);
  4.   rObj.memberFn();
  5.   return 0;
  6. }
  7.  
Hope this helps.


Adrian

Just be careful about accessing shared data structures etc
Yeah, what he said.
Feb 17 '07 #3

P: 52
Here's everything in more detail :

The 3 file are :
1) GridServer.h containing function prototypes
Expand|Select|Wrap|Line Numbers
  1. DWORD WINAPI runThread(LPVOID Parameter);
  2. void startNewThread(SOCKET c_socket);
2) GridServer.cpp ---- the .cpp file with function definitions

Expand|Select|Wrap|Line Numbers
  1. DWORD WINAPI GridServer :: runThread(LPVOID Parameter)
  2. {
  3.     //Get the information about client entity
  4.     SOCKET clientSocket = (SOCKET)Parameter;
  5.  
  6.     printf( "\n New Client Connected.\n");
  7.     cout.flush();
  8.  
  9.     int bytesRecv = SOCKET_ERROR;
  10.     char  *recvbuf;
  11.     recvbuf = new char[1];
  12.  
  13.     int ch ;
  14.     bytesRecv = recv( clientSocket, recvbuf, 1, 0 );
  15.     cout.flush();
  16.  
  17.     printf( "\n Bytes Received: %ld", bytesRecv );
  18.     printf("\n Data Received = %c", recvbuf[0]);
  19.  
  20.     ch = atoi(recvbuf);
  21.  
  22.  
  23.     switch(ch)
  24.     {
  25.         case 1    :    getFile(clientSocket);
  26.                     break;
  27.         case 2  :    createAccount(clientSocket,TABLE_OF_INTEREST);
  28.                     break;
  29.         default    :    printf("\n Invalid option sent from client.");
  30.                     break;
  31.     }
  32.  
  33.     return 0;
  34. }
  35.  
  36. /******************/
  37. void GridServer :: startNewThread(SOCKET c_socket)
  38. {
  39.  
  40.     HANDLE hThread;    //Handle to thread
  41.     DWORD ThreadId;    //used to store the thread id
  42.  
  43.  
  44.     hThread = CreateThread(    NULL,
  45.                             0,
  46.                             &GridServer::runThread,
  47.                             (LPVOID)c_socket,
  48.                             0,
  49.                             &ThreadId);
  50.  
  51.     //printf("\n After CreateThread()");
  52.     return;
  53.  
  54. }
  55.  

and
3) GridServer_Test.cpp ---- the .cpp with main()

it makes a GridServer object named : "ob" and calls
Expand|Select|Wrap|Line Numbers
  1. ob.startNewThread(acceptSocket);
here acceptSocket is a variable of type SOCKET.

now the problems are :

when I compile the code, I get the following error :

Expand|Select|Wrap|Line Numbers
  1. g:\smartsafe\gridserver\gridserver.cpp(207) : error C2664: 'CreateThread' : cannot convert parameter 3 from 'DWORD (__stdcall GridServer::* )(LPVOID)' to 'LPTHREAD_START_ROUTINE'
  2.         There is no context in which this conversion is possible
  3.  
What should I do?
What I require are :
1) calling the runThread() function properly from startNewThread() using CreateThread().
2)Also if you can see that I am calling getFile() and createAccount() from inside the runThread() I want this to be called, with respect to the object which called startNewThread().

I think I have tried to make my code clear this time.
Please Reply, if more information is required, I will reply
Pawan
Feb 18 '07 #4

Expert 100+
P: 1,510
try declaring runThread static
Expand|Select|Wrap|Line Numbers
  1. static DWORD WINAPI GridServer :: runThread(LPVOID Parameter)
  2.  
Feb 18 '07 #5

P: 52
Can you be more elaborate? What changes will be there if I make it static, because someone else told me the other way, I was using static previously in its declaration and definition.

Please reply
Pawan
Feb 18 '07 #6

AdrianH
Expert 100+
P: 1,251
Can you be more elaborate? What changes will be there if I make it static, because someone else told me the other way, I was using static previously in its declaration and definition.

Please reply
Pawan
Expand|Select|Wrap|Line Numbers
  1. DWORD WINAPI GridServer::runThread(LPVOID Parameter)
  2.  
I'm assuming that GridServer is a class.

Now, you cannot pass a member function to CreateThread(). This is because a member function has an implicit pointer passed, namely the this pointer. There are also other things that may be happening 'under the hood' that may not be standard under all C++ implementations.

By declaring the member static, it gets rid of the implicit this pointer and should degrade into a standard C function that has access to objects of the class it was declared in.

But now youíve lost the this pointer. You can no longer access the regular (non-static) member functions in the class because you donít have an object for the member functions to act upon. So to your thread, you must pass a pointer to the object.

So now youíve got a small problem, you need to pass a socket and the object. You can do this in two ways:
  1. Store the socket in the object prior to spawning the thread.
  2. Or create a structure that will hold the socket and a pointer to the object. Create this structure on the heap with the new operator and fill it with the socket and pointer to the object. Pass this structure to the new thread.
On the other side (inside your runThread() function), you will have to recast the pointer to match what you are passing to the CreateThread() function).


Hope this helps.


Adrian
Feb 19 '07 #7

Post your reply

Sign in to post your reply or Sign up for a free account.