How to call static DWORD WINAPI ThreadFunc(LPVOID pvParam)

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • ppuniversal
    New Member
    • Feb 2007
    • 52

    How to call static DWORD WINAPI ThreadFunc(LPVOID pvParam)

    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(LPVO ID 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
  • horace1
    Recognized Expert Top Contributor
    • Nov 2006
    • 1510

    #2
    not sure what the probelm is but you can call functions defined in your program from inside the threaded function. e.g.
    Code:
    #include <iostream>
    #include <windows.h>
    #include <process.h>
    using namespace std;
    
    // function to print an int
    void myFunction(int i)
    {
         cout << "This is prcosses number: " << i << "\n";
    }
    
    // the thread function
    DWORD WINAPI ThreadProc(void *number)
    {    
         int myNumber = *(int*)number;
         myFunction(myNumber);
         _endthread();
    }
    
    // test from to call the thread function 10 times
    int main(int argc, char *argv[])
    {
        int tempNum[10];
        for( int i = 0; i <= 9; i++){
             tempNum[i] = i;
             HANDLE  handle = (HANDLE)CreateThread( NULL, 0, ThreadProc, (void*)&tempNum[i],0, NULL); // create thread
            }  
        system("PAUSE");
        return 0;
    }
    Just be careful about accessing shared data structures etc

    Comment

    • AdrianH
      Recognized Expert Top Contributor
      • Feb 2007
      • 1251

      #3
      Originally posted by horace1
      Code:
               HANDLE  handle = (HANDLE)CreateThread( NULL, 0, ThreadProc, (void*)&tempNum[i],0, NULL); // create thread
      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
      Code:
               HANDLE  handle = (HANDLE)CreateThread(NULL, 0, fooThread, &fooObj, 0, NULL); // create thread
      and you function would be like so:
      Code:
      staic DWORD WINAPI fooThread(void* pObj)
      {
        foo& rObj = *static_cast<foo*>(pObj);
        rObj.memberFn();
        return 0;
      }
      Hope this helps.


      Adrian

      Originally posted by horace1
      Just be careful about accessing shared data structures etc
      Yeah, what he said.

      Comment

      • ppuniversal
        New Member
        • Feb 2007
        • 52

        #4
        Here's everything in more detail :

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

        Code:
        DWORD WINAPI GridServer :: runThread(LPVOID Parameter)
        {
        	//Get the information about client entity
        	SOCKET clientSocket = (SOCKET)Parameter;
        
            printf( "\n New Client Connected.\n");
        	cout.flush();
        
        	int bytesRecv = SOCKET_ERROR;
            char  *recvbuf;
        	recvbuf = new char[1];
        	
            int ch ;
            bytesRecv = recv( clientSocket, recvbuf, 1, 0 );
        	cout.flush();
        
            printf( "\n Bytes Received: %ld", bytesRecv );
        	printf("\n Data Received = %c", recvbuf[0]);
        	
        	ch = atoi(recvbuf);
        	
        	
        	switch(ch)
        	{
        		case 1	:	getFile(clientSocket);
        					break;
        		case 2  :	createAccount(clientSocket,TABLE_OF_INTEREST);
        					break;
        		default	:	printf("\n Invalid option sent from client.");
        					break;
        	}
        	
        	return 0;
        }
        
        /******************/
        void GridServer :: startNewThread(SOCKET c_socket)
        {
        	
        	HANDLE hThread;	//Handle to thread
        	DWORD ThreadId;	//used to store the thread id
        
        
        	hThread = CreateThread(	NULL,
        							0,
        							&GridServer::runThread,
        							(LPVOID)c_socket,
        							0,
        							&ThreadId);
        
        	//printf("\n After CreateThread()");
        	return;
        
        }

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

        it makes a GridServer object named : "ob" and calls
        Code:
        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 :

        Code:
        g:\smartsafe\gridserver\gridserver.cpp(207) : error C2664: 'CreateThread' : cannot convert parameter 3 from 'DWORD (__stdcall GridServer::* )(LPVOID)' to 'LPTHREAD_START_ROUTINE'
                There is no context in which this conversion is possible
        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

        Comment

        • horace1
          Recognized Expert Top Contributor
          • Nov 2006
          • 1510

          #5
          try declaring runThread static
          Code:
          static DWORD WINAPI GridServer :: runThread(LPVOID Parameter)

          Comment

          • ppuniversal
            New Member
            • Feb 2007
            • 52

            #6
            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

            Comment

            • AdrianH
              Recognized Expert Top Contributor
              • Feb 2007
              • 1251

              #7
              Originally posted by ppuniversal
              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
              Code:
              DWORD WINAPI GridServer::runThread(LPVOID Parameter)
              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

              Comment

              Working...