Thread: AfxBeginThread & CreateThread

  1. #1
    Registered User valaris's Avatar
    Join Date
    Jun 2008
    Location
    RING 0
    Posts
    507

    AfxBeginThread & CreateThread

    Heya

    I was attempting to create a thread inside of a class as so:

    Code:
    SomeClass::DoWork()
    {
    ::AfxBeginThread(ThreadProc, NULL);
    }
    
    UINT SomeClass::ThreadProc(LPVOID pArg)
    {
    //work...
    
    return TRUE;
    }
    also I tried to

    Code:
    SomeClass Instance;
    
    ::AfxBeginThread(&Instance.ThreadProc, NULL);
    Basically I'm wondering is it possible in C++ to create a thread inside your object, or create a thread running an objects method? In C# this is no problem, I just cant seem to find any examples of doing this in C++ without making a seperate function outside of a class, or making the class's method static.

    Thanks for any info.

  2. #2
    Reverse Engineer maxorator's Avatar
    Join Date
    Aug 2005
    Location
    Estonia
    Posts
    2,318
    Both AfxBeginThread() and CreateThread() expect an __stdcall calling convention function, but all class methods use __thiscall calling convention, so basically a class method can never be of the same type as AfxBeginThread() requires.
    "The Internet treats censorship as damage and routes around it." - John Gilmore

  3. #3
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    And the solution to this is to pass the "this" as the argument to the function, and then making a static member function that takes a pointer to the class itself, and you can then use the class member functions on the pointer. Something like this:

    Code:
    class SomeClass
    {
    ...
    public:
       __stdcall static ThreadProc(LPVOID pArg);
    
    SomeClass::DoWork()
    {
    ::AfxBeginThread(ThreadProc, this);
    }
    
    UINT SomeClass::ThreadProc(LPVOID pArg)
    {
       SomeClass *myPtr = reinterpret_cast<SomeClass *>(pArg);
    
       myPtr->WorkToBeDoneInThread();
    //work...
    
    return TRUE;
    }
    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by valaris View Post
    Heya

    I was attempting to create a thread inside of a class as so:

    Code:
    SomeClass::DoWork()
    {
    ::AfxBeginThread(ThreadProc, NULL);
    }
    
    UINT SomeClass::ThreadProc(LPVOID pArg)
    {
    //work...
    
    return TRUE;
    }
    also I tried to

    Code:
    SomeClass Instance;
    
    ::AfxBeginThread(&Instance.ThreadProc, NULL);
    Basically I'm wondering is it possible in C++ to create a thread inside your object, or create a thread running an objects method? In C# this is no problem, I just cant seem to find any examples of doing this in C++ without making a seperate function outside of a class, or making the class's method static.

    Thanks for any info.
    The reason is that CreateThread is C, and not C++. AfxBeginThread merely wraps CreateThread, and thus also has a C interface.
    In short, you can blame Microsoft's C compatibility for the lack of this functionality.
    The problem is that these functions really should take an extra argument - the "this" pointer, as explained. That is because there are several instances of a class, so which instance's function should be called?

    However, I made a quick solution that I hope works.
    A C++ variant of CreateThread:

    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;
    }
    
    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); }
    Last edited by Elysia; 01-07-2009 at 04:50 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.

  5. #5
    Registered User valaris's Avatar
    Join Date
    Jun 2008
    Location
    RING 0
    Posts
    507
    Quote Originally Posted by Elysia View Post
    The reason is that CreateThread is C, and not C++. AfxBeginThread merely wraps CreateThread, and thus also has a C interface.
    In short, you can blame Microsoft's C compatibility for the lack of this functionality.
    The problem is that these functions really should take an extra argument - the "this" pointer, as explained. That is because there are several instances of a class, so which instance's function should be called?

    However, I made a quick solution that I hope works.
    A C++ variant of CreateThread:

    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;
    }
    
    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); }
    Hey now this is very cool! And I will steal/borrow/use it ><
    Thanks for everybodies help.

    My last question then would be if &foo::ThreadFunc is how you take the address of a method from within a class, how do you take it (the address of the method) from outside in an object. For using it as a function pointer or some other need?

  6. #6
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,195
    the method will have a fixed address at runtime, so just acquire a pointer to it using this->ThreadFunc not &this->ThreadFunc. C++ does not create a new copy of the function for every instance of the class, just a new copy of the data.

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by valaris View Post
    Hey now this is very cool! And I will steal/borrow/use it ><
    Thanks for everybodies help.
    Feel free

    My last question then would be if &foo::ThreadFunc is how you take the address of a method from within a class, how do you take it (the address of the method) from outside in an object. For using it as a function pointer or some other need?
    It is the same from both within and outside the class. A function has a fixed address (even class functions), so it works inside as well as outside.
    You just need to make sure you pass the proper instance. This varies from inside the class and the outside, of course.

    Quote Originally Posted by abachler View Post
    the method will have a fixed address at runtime, so just acquire a pointer to it using this->ThreadFunc not &this->ThreadFunc. C++ does not create a new copy of the function for every instance of the class, just a new copy of the data.
    This does not work:
    Code:
    	foo() { CPPCreateThread<void>(/*&foo::ThreadFunc*/this->ThreadFunc, this, NULL); }
    Error 1 error C3867: 'foo::ThreadFunc': function call missing argument list; use '&foo::ThreadFunc' to create a pointer to member g:\w00t\documents\visual studio 2008\projects\temp\temp2.cpp 44
    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. CreateThread() function question
    By chiefmonkey in forum C++ Programming
    Replies: 5
    Last Post: 05-15-2009, 07:52 AM
  2. compiler doesn't like CreateThread
    By finkus in forum C++ Programming
    Replies: 6
    Last Post: 11-30-2005, 03:06 AM
  3. sending arguments to function using CreateThread
    By Micko in forum C++ Programming
    Replies: 3
    Last Post: 07-15-2004, 07:07 PM
  4. CreateThread and lpParam
    By Hunter2 in forum Windows Programming
    Replies: 6
    Last Post: 06-02-2004, 04:46 PM
  5. CreateThread() executes ONLY once ... ?
    By SyntaxBubble in forum Windows Programming
    Replies: 5
    Last Post: 11-12-2003, 12:34 PM