threads with member functions

This is a discussion on threads with member functions within the Windows Programming forums, part of the Platform Specific Boards category; this is probably a stupid question with either a really easy answer or an "are u kidding? that can't be ...

  1. #1
    Registered User
    Join Date
    Mar 2006
    Posts
    150

    threads with member functions

    this is probably a stupid question with either a really easy answer or an "are u kidding? that can't be done!!!" answer, but how do i use _beginthread with a class member function? i've tried:

    Code:
    class my_class
    {
     void function_1 (void)
     {
      cout << "Hello, world!";
     }
    };
    
    int main ()
    {
     my_class test;
    
     _beginthread (my_class.function_1, 0, NULL);
    
     return 0;
    }
    to no avail. can anyone tell me how to achieve this?
    HA! I WIN!

  2. #2
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,189
    Quote Originally Posted by xixpsychoxix View Post
    _beginthread (my_class.function_1, 0, NULL);
    Code:
    _beginthread (test.function_1, 0, NULL);
    Last edited by abachler; 02-25-2009 at 04:59 PM.
    Until you can build a working general purpose reprogrammable computer out of basic components from radio shack, you are not fit to call yourself a programmer in my presence. This is cwhizard, signing off.

  3. #3
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,246
    Quote Originally Posted by abachler View Post
    Code:
    _beginthread (test.function_1, 0, NULL);
    How is the "this" pointer going to make it into that call? Or does _beginthread do some special magic?

    When I've done this, I've used a thunk function:

    Code:
    void ThunkMethodCall(void *obj)
    {
        MyClass *myObj = (MyClass *)obj;
        myObj->Foo();
    }
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  4. #4
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,189
    well, generally you pass this as one of the arguments. My personal style is to have it as a seperate function, not part of the class, and simply pass this, which is recast inside the thread.
    Until you can build a working general purpose reprogrammable computer out of basic components from radio shack, you are not fit to call yourself a programmer in my presence. This is cwhizard, signing off.

  5. #5
    Registered User
    Join Date
    Jan 2006
    Location
    Latvia
    Posts
    102
    Or you can make the member function static, but you also need to pass this to it.

  6. #6
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,667
    I'm generous today, so here's my typical C++ CreateNewThread code:
    Code:
    #include <windows.h>
    #include <iostream>
    
    template<typename ParamType, typename ClassType, typename ReturnType>
    	struct ThreadParams
    {
    	ParamType* Param;
    	ClassType* Instance;
    	ReturnType (ClassType::* Function)(ParamType* Param);
    	HANDLE hProcess;
    };
    
    template<typename ParamType, typename ClassType, typename ReturnType>
    	DWORD WINAPI ThreadFnc(void* pParam)
    {
    	ThreadParams<ParamType, ClassType, ReturnType>* pParams =
    	(ThreadParams<ParamType, ClassType, ReturnType>*)pParam;
    	(pParams->Instance->*pParams->Function)(pParams->Param);
    	CloseHandle(pParams->hProcess);
    	delete pParams;
    	return 0;
    }
    
    template<typename ParamType, typename ClassType, typename ReturnType>
    	DWORD CPPCreateThread(ReturnType (ClassType::* Function)(
    	ParamType* Param), ClassType* Instance, ParamType* Param)
    {
    	ThreadParams<ParamType, ClassType, ReturnType>* pParams =
    		new ThreadParams<ParamType, ClassType, ReturnType>;
    	pParams->Param = Param;
    	pParams->Instance = Instance;
    	pParams->Function = Function;
    	HANDLE hProcess = CreateThread(NULL, NULL,
    		&ThreadFnc<ParamType, ClassType, ReturnType>, pParams,
    		CREATE_SUSPENDED, NULL);
    	if (hProcess == NULL)
    		return GetLastError();
    	pParams->hProcess = hProcess;
    	ResumeThread(hProcess);
    	DWORD dwErr = GetLastError();
    	if (dwErr != ERROR_SUCCESS)
    	{
    		CloseHandle(hProcess);
    		delete pParams;
    	}
    	return dwErr;
    }
    
    // THIS IS HOW YOU USE IT, FROM HERE ON OUT
    class foo
    {
    public:
    	foo() { CPPCreateThread<void>(&foo::ThreadFunc, this, NULL); }
    	void ThreadFunc(void*) { std::cout << "Hi! This is inside the thread!"; };
    };
    
    int main() { foo f; Sleep(1000); }
    There. Does that help?
    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.

  7. #7
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,893
    Whatever you do, don't use _beginthread. It's conceptually broken. Use _beginthreadex if you want the CRT (you probably do) or CreateThread if you don't.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  8. #8
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    611
    Quote Originally Posted by Elysia View Post
    Does that help?
    Great stuff, thanks for posting. The only problem I have is that it's in the wrong thread, I think you wanted this one

  9. #9
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,667
    Now why would you think something like that?
    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.

  10. #10
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,893
    I see four problems with your code, Elysia.

    1) You're calling the thread handle hProcess. This is the least of the problems, though, just a confusing name.
    2) You're not using _beginthreadex. If you link statically against the CRT, that will leak. Not good for a generic utility.
    3) You're passing the returned handle to the created thread. What for? It's your handle, just close it. If the created thread wants a real handle to itself, it can DuplicateHandle(GetCurrentThread()). Your thread stub doesn't even use the handle!
    4) You're leaking pParams if thread creation fails.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  11. #11
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,667
    1) I don't know why I named it hProcess... Perhaps I was confusing it with something else. My mistake.
    2) That is a good point. I didn't know about that before...
    3) Well... I used it to close the handle from the thread itself. I dunno if it's possible to do it right after the call or not.
    4) Oops!

    So I revamped the code a little to get rid of the criticism.
    EDIT: Posting fixed code below.
    Last edited by Elysia; 02-27-2009 at 03:10 AM.
    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.

  12. #12
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    611
    Here's 4 more

    1. Still leaking pParams if ResumeThread fails
    2. Leaking at least the thread stack on Vista+ if ResumeThread fails (call TerminateThread to get rid of it).
    3. Relying on GetLastError to return 0 when a function succeeds isn't guaranteed (especially not for a CRT function). Checking the return value is easier.

    And since this is intended for C++
    4. pParam will leak if the thread function throws.

  13. #13
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,667
    Very well. Revised code.
    I hope this one gets rid of all criticism.

    Code:
    #include <windows.h>
    #include <iostream>
    #include <process.h>
    #include <memory>
    
    namespace Stuff
    {
    	typedef unsigned int (__stdcall CThreadFunction)(void*);
    	template<typename T> CThreadFunction* CThreadFunctionCast(
    		unsigned int (__stdcall* pFunction)(T*))
    	{
    		return reinterpret_cast<CThreadFunction*>(pFunction);
    	}
    
    	class auto_handle
    	{
    	public:
    		auto_handle(HANDLE Handle): m_h(Handle) {}
    		~auto_handle() { CloseHandle(m_h); }
    		HANDLE get() { return m_h; }
    
    	private:
    		HANDLE m_h;
    	};
    
    	template<typename T> class reference_wrapper
    	{
    		reference_wrapper(T& value): m_value(value) {}
    
    	private:
    		T& m_value;
    	};
    
    	int get_err_no()
    	{
    		int temp;
    		_get_errno(&temp);
    		return temp;
    	}
    
    	namespace Thread
    	{
    		struct Error
    		{
    			int CreationError;
    			DWORD ResumeError;
    			DWORD TerminateError;
    		};
    
    		template<typename ParamType, typename ClassType, typename ReturnType>
    			struct Params
    		{
    			ParamType* Param;
    			ClassType* Instance;
    			ReturnType (ClassType::* Function)(ParamType* Param);
    		};
    
    		template<typename ParamType, typename ClassType, typename ReturnType>
    			unsigned int __stdcall ThreadFnc(
    			Params<ParamType, ClassType, ReturnType>* pParam)
    		{
    			(pParam->Instance->*pParam->Function)(pParam->Param);
    			delete pParam;
    			return 0;
    		}
    
    		template<typename ParamType, typename ClassType, typename ReturnType>
    			Error Create(ReturnType (ClassType::* Function)(ParamType* Param),
    			ClassType* Instance, ParamType* Param)
    		{
    			const DWORD dwFail = static_cast<DWORD>(-1);
    			Error ReturnErr = {};
    			std::auto_ptr< Params<ParamType, ClassType, ReturnType> > pParams(
    				new Params<ParamType, ClassType, ReturnType>);
    			pParams->Param = Param;
    			pParams->Instance = Instance;
    			pParams->Function = Function;
    			Stuff::auto_handle hThread = reinterpret_cast<HANDLE>(
    				_beginthreadex(NULL, 0, Stuff::CThreadFunctionCast(
    					&ThreadFnc<ParamType, ClassType, ReturnType>),
    				pParams.get(), CREATE_SUSPENDED, NULL) );
    			if (hThread.get() == 0)
    			{
    				ReturnErr.CreationError = Stuff::get_err_no();
    				return ReturnErr;
    			}
    			if (ResumeThread(hThread.get()) == dwFail)
    			{
    				ReturnErr.ResumeError = GetLastError();
    				if ( !TerminateThread(hThread.get(), 1) )
    					ReturnErr.TerminateError = GetLastError();
    				return ReturnErr;
    			}
    			pParams.release();
    			return ReturnErr;
    		}
    	}
    }
    
    class foo
    {
    public:
    	foo() { Stuff::Thread::Create<void>(&foo::ThreadFunc, this, NULL); }
    	void ThreadFunc(void*) { std::cout << "Hi! This is inside the thread!"; };
    };
    
    int main() 
    {
    	foo f;
    	Sleep(1000);
    }
    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.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Callbacks to member functions
    By prog-bman in forum C++ Programming
    Replies: 0
    Last Post: 01-19-2008, 01:48 AM
  2. Pointers to member functions using virtual methods
    By Will B-R in forum C++ Programming
    Replies: 2
    Last Post: 05-26-2006, 06:59 AM
  3. Array of member functions
    By Ward in forum C++ Programming
    Replies: 7
    Last Post: 04-05-2006, 07:47 AM
  4. Templates for member functions
    By reachb4 in forum C++ Programming
    Replies: 1
    Last Post: 07-01-2005, 04:53 AM
  5. How do you call member functions
    By Elite in forum C++ Programming
    Replies: 7
    Last Post: 08-05-2003, 01:03 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21