Thread: problem threading a member function

  1. #1
    Registered User
    Join Date
    Mar 2002
    Posts
    203

    problem threading a member function

    I'm having problems using a simple Threading library from a book i'm reading (Mud Game Programming). It isn't working when the function I want to thread is a member of a class I create. Other than removing ThreadFunc from MyClass, how could I code around my problem?

    Code:
    class MyClass
    {
    protected:
    	ThreadLib::ThreadID TID_ThreadID;
    	void ThreadFunc(void *);
    public:
    	void MyFunc();
    };
    
    void MyClass::MyFunc()
    {
    	TID_ThreadID = ThreadLib::Create( ThreadFunc, (void*)NULL );
    }
    
    void MyClass::ThreadFunc(void *)
    {
    
    }
    Code:
    //Related ThreadLib code
    //from header file
    namespace ThreadLib
    {
    	typedef void (*ThreadFunc)(void*);
    	typedef DWORD ThreadID;
    	extern std::map< DWORD, HANDLE > g_handlemap;
    	class DummyData
    	{
    	public:
    		ThreadFunc m_func;
    		void* m_data;
    	};
    	DWORD WINAPI DummyRun( void* p_data );
    	ThreadID Create( ThreadFunc p_func, void* p_param )
    	{
    		ThreadID t;
    		DummyData* data = new DummyData;
    		data->m_func = p_func;
    		data->m_data = p_param;
    		HANDLE h;
    		h = CreateThread( NULL, 0, DummyRun, data, 0, &t );
    		if( h != 0 )
    			g_handlemap[t] = h;
    		if( t == 0 )
    		{
    			delete data;
    			throw Exception( CreationFailure );
    		}
    		return t;
    	}
    }
    
    //from cpp
    namespace ThreadLib
    {
    	std::map< DWORD, HANDLE > g_handlemap;
    	DWORD WINAPI DummyRun( void* p_data )
    	{
    		DummyData* data = (DummyData*)p_data;
    		data->m_func( data->m_data );
    		delete data;
    		return 0;
    	}
    }

    The error I get:
    "error C3867: MyClass::ThreadFunc: function call missing argument list; use '&MyClass::ThreadFunc' to create a pointer to member"

    The error I get if it's &MyClass::ThreadFunc
    "error C2664: 'ThreadLib::Create' : cannot convert parameter 1 from 'void (__thiscall MyClass::* )(void *)' to 'ThreadLib::ThreadFunc'
    There is no context in which this conversion is possible"

    The error I get if i try to cast it to a void*
    "error C2440: 'initializing' : cannot convert from 'void (__thiscall MyClass::* )(void *)' to 'void *'"

    <edit> The posted ThreadLib only shows what was defined as win32. I removed all defines, if/else, for anything other than win32 to make it easier to read. The author wrote the library for both windows and linux.
    Last edited by Syneris; 01-27-2006 at 04:02 PM.

  2. #2
    Registered User
    Join Date
    Nov 2005
    Posts
    52
    The problem you have while using &MyClass::ThreadFunc (which , btw, is what you really WANT to use), is that MyClass::ThreadFunc doesn't actually match the function signature of the ThreadFunc function pointer, due to the fact that it has an (unlisted) argument - the this pointer. In a case like this, you can either use the helper functions in <functional>, like mem_fun and its kin, or you can write your thread function as a free function, and pass in a pointer to your class instance as needed. A third option would be to use Boost.Thread, which is all but guaranteed to be at least as good, and likely better, than the library written for that book.

  3. #3
    Registered User
    Join Date
    Mar 2002
    Posts
    203
    Thanks, I'll look into your suggestions. MyClass has private members that are used in the function, so making it a member function would be best. I downloaded boost already during my searching, but the instructions for setting it up was a little confusing. I'll search some more on how to setup boost and use it.

  4. #4
    Registered User
    Join Date
    Mar 2002
    Posts
    203
    Trying to just CreateThread isn't working either. It gives "error C2664: 'CreateThread' : cannot convert parameter 3 from 'DWORD (__stdcall MyClass::* )(LPVOID)' to 'LPTHREAD_START_ROUTINE' There is no context in which this conversion is possible"
    I haven't had any luck with Boost yet
    Making a member a function pointer to the function seems to work. I can make it a friend to access the private members, but i have to pass it a pointer to the MyClass instance that calls it or I don't have the data. Is this an acceptable implementation? And if MyClass is a member inside of another class, is there a simple way for ThreadFunc to communicate with the class it's a member of without returning from the function?

  5. #5
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    That error looks like you're having problems with function pointers.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  6. #6
    Registered User
    Join Date
    Mar 2002
    Posts
    203
    Now I've run into a potential problem passing a pointer to the class to use inside the thread function. If MyClass changes it's location in memory (like if I have a vector of MyClass and it resizes) then the pointer I passed is no longer pointing to the right spot, correct?

  7. #7
    carry on JaWiB's Avatar
    Join Date
    Feb 2003
    Location
    Seattle, WA
    Posts
    1,972
    For a vector, you go past the value given by the capacity() function, then it has to reallocate and any iterators/pointers/references you have are invalid. For lists, sets, multisets, maps, and multimaps, inserting or removing elements never invalidates pointers/iterators/references
    "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

  8. #8
    Registered User
    Join Date
    Dec 2008
    Posts
    1
    The solution is simply change "DummyRun" function type to:

    Code:
    static unsigned _stdcall DummyRun( void* p_data );
    Define your CreateThread with:

    Code:
    h = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE) DummyRun, data, 0, &t );
    and then in the CPP, implement with:

    Code:
    unsigned _stdcall DummyData::DummyRun( void* p_data )
    {
        DummyData* data = (DummyData*)p_data;
        data->m_func( data->m_data );
       delete data;
       return 0;
    }

  9. #9
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,195
    To use CreateThread the function has to be DWORD WINAPI Func(LPVOID)

    Code:
    class MyClass
    
    {
    
    protected:
    
        ThreadLib::ThreadID TID_ThreadID;
    
        DWORD WINAPI ThreadFunc(LPVOID);
    
    public:
    
        void MyFunc();
    
    };
    then it will work like this -

    Code:
    ThreadHandle = CreateThread(NULL , 0 , this->ThreadFunc , NULL , 0 , &ThreadID);
    Last edited by abachler; 12-31-2008 at 05:01 AM.

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Never cast a function pointer unless you are really, really, really, really, really SURE what you are doing!
    If you have done it correctly, no cast is necessary!

    Also, this is a common misconception...
    A global function is just that - a function of which there is only one instance.
    However, when working with classes, you are working with instances of the classes. So which instance of the function are you trying to call?
    You see the problem here, yes? That is why you cannot use a class member function as a callback function. The API was not designed for it. You have to use workarounds.

    Also, when creating a function pointer, usually we need to take the address of the function. For global functions, you can get away with only typing the name - but this is really wrong. You should use the address-of operator &. This is even more obvious when trying to pass a function pointer to a member function of a class where it is required. It is not necessary for global functions for backwards compatibility only.
    Also, when working with class member functions, you need to pass the instance the function belongs to, as well.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #11
    Registered User
    Join Date
    Mar 2002
    Posts
    203
    topic is 2 years old.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 04-19-2008, 12:06 AM
  2. Replies: 3
    Last Post: 06-23-2005, 06:39 PM
  3. problem returning struct member from function
    By yukster in forum C Programming
    Replies: 6
    Last Post: 08-24-2003, 01:21 PM
  4. structure vs class
    By sana in forum C++ Programming
    Replies: 13
    Last Post: 12-02-2002, 07:18 AM
  5. Pointer to member function as callback function
    By ninebit in forum C++ Programming
    Replies: 10
    Last Post: 03-01-2002, 05:52 AM