Thread: Calling a Thread with a Function Pointer.

  1. #1
    Registered User
    Join Date
    Jun 2006
    Posts
    4

    Exclamation Calling a Thread with a Function Pointer.

    Does this Question Belong in Windows Programming Category?
    I believe the following question belongs under Windows Programming Catergory because I am working with multithreading on a windows system.

    What OS, Compiler and IDE are you Using?

    • I am developing a console applcation for Windows XP that will be using multithreading
    • I am using Borland C++ Compiler 5.5
    • I am doing this all in Notepad++


    What are you Trying to Do?

    I have a class that is a singelton that creates, kills and yeilds threads for the most part. With the Create Function I have two parameters for a typedef of a function pointer for the thread I wish to create and a secound parameter for thats thread paratmeter. these parameter get past into the CreateThread function that is inside the function body of my Create function.

    What is your Question ( AKA your Problem)?

    When I pass my two parameters into the CreateThread parameters I get the resulting error.

    This is what the compiler spews out
    Code:
    C:\Borland\Projects\MUD>bcc32 test
    Borland C++ 5.6.4 for Win32 Copyright (c) 1993, 2002 Borland
    test.cpp:
    Error E2034 MUDThread.h 19: Cannot convert 'void (*)(void *)' to 'unsigned long
    (__stdcall *)(void *)' in function MUDThread::Create(void (*)(void *),void *)
    Error E2342 MUDThread.h 19: Type mismatch in parameter 'lpStartAddress' (wanted
    'unsigned long (__stdcall *)(void *)', got 'void (*)(void *)') in function MUDTh
    read::Create(void (*)(void *),void *)
    Error E2176 test.cpp 3: Too many types in declaration
    Error E2111 test.cpp 4: Type 'MUDThread' may not be defined here
    Warning W8070 test.cpp 13: Function should return a value in function PrintThrea
    d(void *)
    Error E2451 test.cpp 17: Undefined symbol 'ThreadID' in function main()
    Error E2379 test.cpp 17: Statement missing ; in function main()
    Error E2451 test.cpp 18: Undefined symbol 'a' in function main()
    Error E2247 test.cpp 18: 'MUDThread::Create(void (*)(void *),void *)' is not acc
    essible in function main()
    Error E2283 test.cpp 18: Use . or -> to call 'MUDThread::Create(void (*)(void *)
    ,void *)' in function main()
    Error E2451 test.cpp 19: Undefined symbol 'b' in function main()
    Error E2247 test.cpp 19: 'MUDThread::Create(void (*)(void *),void *)' is not acc
    essible in function main()
    Error E2283 test.cpp 19: Use . or -> to call 'MUDThread::Create(void (*)(void *)
    ,void *)' in function main()
    Error E2247 test.cpp 21: 'MUDThread::WaitForFinish(unsigned long)' is not access
    ible in function main()
    Error E2283 test.cpp 21: Use . or -> to call 'MUDThread::WaitForFinish(unsigned
    long)' in function main()
    Error E2247 test.cpp 22: 'MUDThread::WaitForFinish(unsigned long)' is not access
    ible in function main()
    Error E2283 test.cpp 22: Use . or -> to call 'MUDThread::WaitForFinish(unsigned
    long)' in function main()
    
    *** 16 errors in Compile ***
    So my problem is that the function I am passing in does not match my typedef. I am unsure as to what I need to change in my typedef so that I dont have this error.

    Cannot convert 'void (*)(void *)' to 'unsigned long
    (__stdcall *)(void *)'

    The obvious difference is that the Thread Function I am trying to convert is using a windows calling convention and is returning a unsigned long. I want my Create function to have the flexiblity to handle, for the most part any type of thread function thrown at it

    Also if I haven't noted I am following the MUD Programming Book by Ron Penton.

    How can we help if you haven't shown us your Code?

    Oh sorry here it is.

    test.cpp is the code that is calling MUDThread class.
    Code:
    #include "MUDThread.h"
    
    void PrintThread( void* data ) 
    {
        // convert the data passed in into a character.
        char c = (char)data;
    
        for( int i = 0; i < 10000; i++ ) 
    	{
            cout << c;
            cout.flush();
        }
    }
    
    int main() 
    {
        MUDThread::ThreadID a, b;
        a = MUDThread::Create( PrintThread, (void*)'a' );
        b = MUDThread::Create( PrintThread, (void*)'b' );
    
        MUDThread::WaitForFinish( b );
        MUDThread::WaitForFinish( a );
    
        char c;
        cin >> c;
        return 0;
    }

    This is the Class that handles creating thread functions, killing and yeilding them.
    Code:
    #include <windows.h>
    #include <map.h>
    #include <iostream>
    using namespace std;
    
    typedef DWORD ThreadID;
    std::map< DWORD, HANDLE > g_handlemap;
    typedef void ( *thFunc)(void*); 
     
    class MUDThread
    {
    
    	// CREATE THREAD
    	inline ThreadID Create( thFunc p_func, void* p_param )
    	{
    		ThreadID t;
    
    		HANDLE h;
    		h = CreateThread( NULL, 0, p_func, p_param, 0, &t );
    		
    		if( h != 0 ) 
    			g_handlemap[t] = h; // insert the handle into the handlemap
    	}
    
    	// KILL THREAD
    	inline void Kill( ThreadID& p_thread )
    	{
            TerminateThread( g_handlemap[p_thread], 0 ); //Terminate the thread
            CloseHandle( g_handlemap[p_thread] ); 		 //Close the handle of the thread   
            g_handlemap.erase( p_thread );				 //Remove HANDLE from map
    	}
    	// GET THREAD ID
    	inline ThreadID GetID() 
    	{
    		return GetCurrentThreadId();
    	}
    	// WAIT FOR THREAD TO FINISH
    	inline void WaitForFinish( ThreadID p_thread ) 
    	{ 
            WaitForSingleObject( g_handlemap[p_thread], INFINITE ); //Look up the handle and wait for the thread to finish											
            CloseHandle( g_handlemap[p_thread] );					//Close the handle of the thread  
            g_handlemap.erase( p_thread ); 							//Remove the handle from the map
    	}
    	// YEILD THREAD
    	inline void YieldThread( int p_milliseconds = 1 ) 
    	{
            Sleep( p_milliseconds );
    	}
    	
    }

    Can you show some respect and do some groveling?

    Please I beg of you. Oh Mighty Coders from the North Frigided Ice Lands!, For you are but My only hope to solve my Encumbersome Coding Misfortuntes, And I aplogize for my Awful Use of Gammer and Spelling Mistakes For I am too Dumb to Use a Spell Checker.

  2. #2
    carry on JaWiB's Avatar
    Join Date
    Feb 2003
    Location
    Seattle, WA
    Posts
    1,972
    >The obvious difference is that the Thread Function I am trying to convert is using a windows calling convention and is returning a unsigned long. I want my Create function to have the flexiblity to handle, for the most part any type of thread function thrown at it

    I'm not sure you can do that. Can't you just have the function you pass to CreateThread call another function? Maybe something along the lines of:
    Code:
    struct FooStruct
    {
      int a, b, c;
    };
    
    void FooThreadProc(int a, int b, int c)
    {
    //...
    }
    DWORD WINAPI FooThreadStartProc(LPVOID params)
    {
      FooStruct* fs = reinterpret_cast<FooStruct*>(params);
      FooThreadProc(fs->a,fs->b,fs->c);
    }
    And your class isn't a singleton. There isn't even a static function in it
    Last edited by JaWiB; 06-09-2006 at 09:20 PM. Reason: Syntax errors
    "Think not but that I know these things; or think
    I know them not: not therefore am I short
    Of knowing what I ought."
    -John Milton, Paradise Regained (1671)

    "Work hard and it might happen."
    -XSquared

  3. #3
    Registered User
    Join Date
    Jun 2006
    Posts
    4
    Well I should restate that my intended use of that class will be a singleton, I will not be creating an instance of that class but only calling its member functions with the scope operator. I still need to declare it as a static class and make sure that it cannot be constructed.

    I have attached a Image to show in much simpilar terms as to what I am trying to do.

    The MUD book I am following did not have to cast any type, as well my C++ Primer book gave me some advice.

    !!Advice: Avoid Casts!!

    I would like either two things as an anwser,

    A: If someone could attempt to solve and compile my code to get it to work.

    B: Show or create me an example of a Function or a Member Function that calls CreateThread() and that function should pass on the two parameters that CreateThread needs to create a thread, A pointer to the function thread and its parameter.
    Last edited by ScrollMaster; 06-09-2006 at 10:18 PM.

  4. #4
    erstwhile
    Join Date
    Jan 2002
    Posts
    2,227
    >>!!Advice: Avoid Casts!!<<

    The winapi is a c-interface; if you're coding with it in c++ you'll be doing a lot of casting.

    That aside, JaWiB's example provides the information you need; if you need the ThreadProc to be a member function of a C++ class then declare it as static.

    If you spent a fraction of the time searching this board as you did on your sardonically obsequious first post you would have found lots of useful examples; for instance, this approach uses functors. This page provides an interesting approach, too, which demonstrates how flexible you can be with winapi function pointer types.

    map.h is non-standard; use <map> instead. If your compiler complains about that then get another; dev-cpp(mingw) and msvc-express are free and very good. Alternatively, use a better stl implementation than that provided by your compiler - stlport, for example.

    >>If someone could attempt to solve and compile my code to get it to work.<<

    You'll need to post/attach a minimal example that replicates the problem; it may be that by constructing such an example and applying the information so far provided that you'll have sufficient understanding of the problem to solve it yourself.

    Welcome to the boards.
    CProgramming FAQ
    Caution: this person may be a carrier of the misinformation virus.

  5. #5
    Registered User
    Join Date
    Jun 2006
    Posts
    4
    I had spent enough time searching the boards and because I had not found the anwser. I Ussually avoid posting for questions but it has been a few days and I can't figure it out and would like to progress.

    I only questioned the use of the cast because my book had not used it as well my C++ Primer Book states exactly this: "Advice: Avoid Casts". So Im trying to do just that.

    I don't quite understand the example given.
    I believe I would have an easier time understanding it if I saw an example implemented in my already existing code or an example using CreateThread().

    I had not attached the file. I will remember that in the future. Although I had posted my code exactly how it was when resulting with the error as well as the what the compiler spewed out as errors so I thought it could be easily copied and pasted into a texteditor.

    sardonically obsequious first post (
    ?mocking with favour?)

    I do alot of forum searching and when I make posts I like to structure them in a question and anwser way. I had not used any saracasm what so ever. I take time into preparing my post so that all questions are hopefully anwsered, as well for people who may stumble upon this problem if they search they will be able to find their anwser. I used terminology not to sound smart but that when someone searches the forums they will find a more exact anwser.

    Also my groveling was not saracasm, I was paying my respect to those who will be helping me and I like to have a bit of fun writing it to.

    I will have to read and break down thoes resources you ahve found Ken.
    I had stumbled upon that big one but had not known if it had the anwser I wanted.

    Also Borland is the Way, And All Should Conform to it!

    Thanks Ken, but still I wouldnt mind an example function that handles creating threads.

  6. #6
    Registered User Dante Shamest's Avatar
    Join Date
    Apr 2003
    Posts
    970
    I've written a simple Thread wrapper that may be helpful.
    Here's how to use it.
    1. Create your own class that inherits from the Thread class.
    2. Override the virtual run() member function and put code you wish the thread to run in there.
    3. Call the start() member function to start the thread.
    4. Call the stop() member function to stop the thread. (Note: stop() calls TerminateThread() which can cause memory leaks; so it would be better if you found some other way to exit the run() method gracefully).

    Thread.h
    Code:
    #ifndef THREAD_H
    #define THREAD_H
    #include <windows.h>
    #include <process.h>
    
    class Thread {
    public:
    
      Thread()
        : thread()
        , running( false )
      {}
    
      virtual ~Thread()
      {
        stop() ;
      }
    
      bool start()
      {
        if ( !running ) 
        {
          thread = (HANDLE)_beginthreadex( NULL,
                                           0,
                                           Thread::threadProc, 
                                           this,
                                           0,
                                           0 ) ;
    
          return thread != NULL ;
        }
        return false ;
      }
    
      void stop() {
        if ( thread ) {
          if ( running ) {
            TerminateThread( thread, 0 ) ;
            running = false ;
          }
          CloseHandle( thread ) ;
          thread = NULL ;
        }
      }
    
      virtual void run() {
        
      }
    
      bool isRunning() const
      {
        return running ;
      }
    
    private:
    
      Thread( const Thread& );
      Thread& operator=( const Thread& );
    
      static unsigned __stdcall  threadProc( void * arg ) {
        Thread* t = (Thread*) arg ;
        t->running = true ;
        t->run() ;
        t->running = false ;
        return 0 ;
      }
    
    private:
    
      HANDLE thread ;
      bool   running ;
    
    };
    
    #endif
    Here's code that uses the Thread class.

    main.cpp
    Code:
    #include "Thread.h"
    
    
    class Label {
    public:
    
      Label()
        : hwnd()
      {}
    
      bool create( HWND    parent, 
                   LPCTSTR text = 0, 
                   DWORD   style  = WS_CHILD|WS_VISIBLE|SS_CENTERIMAGE, 
                   DWORD   stylex = 0,
                   int     x=0, 
                   int     y=0, 
                   int     w=0, 
                   int     h=0 )
      {
        hwnd = CreateWindowEx( stylex, TEXT("Static"), text, style, x, y, w, h,
                               parent, 0, GetModuleHandle(0), 0 );
    
        return NULL != hwnd ;
      }
    
      void setHandle( HWND h ) {
        hwnd = h ;
      }
    
      HWND getHandle() const {
        return hwnd ;
      }
    
      void setText( LPCTSTR text ) {
        SetWindowText( hwnd, text ) ;
      }
    
    private:
      HWND hwnd ;
    };
    
    class Button {
    public:
    
      Button()
        : hwnd()
      {}
    
      bool create( HWND    parent, 
                   LPCTSTR text = 0, 
                   DWORD   style  = WS_CHILD|WS_VISIBLE, 
                   DWORD   stylex = 0,
                   int     x=0, 
                   int     y=0, 
                   int     w=0, 
                   int     h=0 )
      {
        hwnd = CreateWindowEx( stylex, TEXT("Button"), text, style, x, y, w, h, parent,
                               0, GetModuleHandle(0), 0 );
    
        return NULL != hwnd ;
      }
    
      void setHandle( HWND h ) {
        hwnd = h ;
      }
    
      HWND getHandle() const {
        return hwnd ;
      }
    
      void setText( LPCTSTR text ) {
        SetWindowText( hwnd, text ) ;
      }
    
    private:
      HWND hwnd ;
    };
    
    class CounterThread : public Thread {
    public:
    
      virtual void run() {
        int i = 0 ;
        int past = GetTickCount() ;
        while ( i < 100 ) {
          int now = GetTickCount() ;
          if ( now - past > 100 ) {
            past = now ;
            ++i ;
            TCHAR buf[ 100 ] ;
            wsprintf( buf, "%d", i ) ;
            label.setText( buf ) ;
          }
          Sleep( 10 );
        }
      }
    
      void setLabel( HWND hwnd ) {
        label.setHandle( hwnd ) ;
      }
    
    private:
    
      Label label ;
    
    };
    
    Button startButton, stopButton ;
    Label  label ;
    CounterThread counterThread ;
    
    LRESULT CALLBACK WndProc( HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam )
    {
      switch(msg)  
      {
        case WM_CREATE: {
          startButton.create( hwnd, TEXT("Start"), WS_CHILD|WS_VISIBLE, 
                         0, 
                         10, 10, 80, 22 );
          stopButton.create( hwnd, TEXT("Stop"), WS_CHILD|WS_VISIBLE, 
                         0, 
                         100, 10, 80, 22 );
          label.create( hwnd, TEXT("0%"), WS_CHILD|WS_VISIBLE|SS_CENTERIMAGE, 0,
                         10, 40, 80, 22 ) ;
    
          counterThread.setLabel( label.getHandle() );
    
          if ( label.getHandle() == NULL ) {
            return 1 ;
          }
    
          return 0 ;
        }
    
        case WM_COMMAND:
        {
          HWND ctrl = (HWND) lParam ;
    
          if ( ctrl == startButton.getHandle() ) {
            if ( !counterThread.isRunning() ) {
              if ( !counterThread.start() ) {
                MessageBox( hwnd, TEXT("Error creating thread"), 0, 0 );
              }
            }
          }
          else if ( ctrl == stopButton.getHandle() ) {
            counterThread.stop() ;
          }
    
          return 0 ;
        }
    
        case WM_DESTROY:
          {
            PostQuitMessage(0);
            return 0;
          }
          
        default: return DefWindowProc(hwnd,msg,wParam,lParam);
      }
    }
    
    int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrev, LPSTR args, int nShow )
    {
      MSG  msg ;    
      WNDCLASS wc = {0};
      wc.lpszClassName = TEXT( "Boilerplate" );
      wc.hInstance     = hInst ;
      wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
      wc.lpfnWndProc   = WndProc ;
      wc.hCursor       = LoadCursor(0,IDC_ARROW);
      
      RegisterClass(&wc);
      CreateWindow( wc.lpszClassName,TEXT("Boilerplate Windows Program"),
                    WS_OVERLAPPEDWINDOW|WS_VISIBLE,
                    0,0,300,200,0,0,hInst,0);  
    
      while( GetMessage(&msg,0,0,0) > 0 ) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
      return (int)msg.wParam;
    }
    Last edited by Dante Shamest; 06-10-2006 at 07:52 AM.

  7. #7
    Registered User
    Join Date
    Jun 2006
    Posts
    4
    I am not yet ready to start making Mutlthread Windowed Applications but that looks like something that will come in handy soon enough.

    I am going back step through step. I think Ill be overcoming my problem soon enough. I will give this code a good look over

    !!Thanks.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Undefined Reference Compiling Error
    By AlakaAlaki in forum C++ Programming
    Replies: 1
    Last Post: 06-27-2008, 11:45 AM
  2. dllimport function not allowed
    By steve1_rm in forum C++ Programming
    Replies: 5
    Last Post: 03-11-2008, 03:33 AM
  3. What is a virtual function pointer?
    By ting in forum C++ Programming
    Replies: 4
    Last Post: 03-05-2008, 02:36 AM
  4. calling a function with a pointer to a struct
    By bomberto in forum C++ Programming
    Replies: 1
    Last Post: 10-01-2006, 04:21 AM
  5. Direct3D problem
    By cboard_member in forum Game Programming
    Replies: 10
    Last Post: 04-09-2006, 03:36 AM