• Advertisement

Archived

This topic is now archived and is closed to further replies.

How to start a thread in Win32 C++

This topic is 5556 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, i read about the _beginThread function but I can't use it because I use c++ (or is there a way to use it anyway with a c++ function of my class?). how to start a thread using C++ ? EDIT: I do not want to use MFC - so please don't tell me this is the only way to go.... thank you [edited by - Dominik_78 on December 6, 2002 2:45:09 PM]

Share this post


Link to post
Share on other sites
Advertisement
d:\projects\maddogcombat\ssengine.cpp(42) : error C2664: ''_beginthread'' : cannot convert parameter 1 from ''void (void)'' to ''void (__cdecl *)(void *)''

what does this mean?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
It means you need to typecast the thing you are passing in to a void*

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
And yes, you can use beginthread with c++. Just read the doc, it tells you exactly what to do.

Share this post


Link to post
Share on other sites
then this comes up:

d:\projects\maddogcombat\ssengine.cpp(42) : error C2440: ''type cast'' : cannot convert from ''void (__thiscall CSSEngine::*)(void)'' to ''void *''

Share this post


Link to post
Share on other sites
i did as the doc told but the compiler error came up.

if i compile the example everything is ok.

and the only difference i see ic c <> c++

just because i am using classes?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
[url="http://www.experts-exchange.com/Programming/Programming_Platforms/Win_Prog/Q_10168718.html"]This might help...[/url]

Share this post


Link to post
Share on other sites
that is because of the API not because of the syntax. Its because you created a class reference as an entry point for a API. Which is not allowed in that context. You must make the entry point function static. Then you must Make any variables that it will use static also.


If you have read the K&R reference manual, in basic c this would be clear on c/c++ API or static variables.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
this might help also: http://www.experts-exchange.com/Programming/Programming_Languages/Cplusplus/Q_20117462.html

Share this post


Link to post
Share on other sites
Sorry for my dumness but i can''t figure out what i have to do at all - define my function static? is that all?

Share this post


Link to post
Share on other sites
Define it static, then pass the "this" pointer to the thread function. Then you can cast the void pointer you get in the thread function to a pointer to your class and call whatever you want.

What I normally do is have a static function called StaticThreadProc, then delegate to the non-static ThreadProc.


Helpful links:
How To Ask Questions The Smart Way | Google can help with your question | Search MSDN for help with standard C or Windows functions

Share this post


Link to post
Share on other sites
Actually, beginthreadex is preferred over beginthread. Here is a macro that you might find helpful. You might also find these urls informative.


      
/* createthreadex.h */
#ifndef CREATETHREADEX_H_
#define CREATETHREADEX_H_

#pragma once

#include <process.h>

/* ---------------------------------------------------------------------------
Q132078: "How to Use _beginthreadex() and _endthreadex()"
http://support.microsoft.com/default.aspx?scid=KB;EN-US;q132078&

When developing a multithreaded Win32-based application with Visual C++,
you need to use the CRT thread functions to create any threads that call
CRT functions. To create and terminate threads, use either _beginthread()
and _endthread() or _beginthreadex() and _endthreadex().

If you use the Win32 APIs CreateThread() and ExitThread() instead,
some of the CRT functions used in the thread will not work.
You need to use the CRT functions to both create and end the threads
or you lose the memory that the CRT allocates for the thread.

In addition to preventing memory leaks, using _beginthreadex places
a structured exception handling frame around the thread function
so that the signal function and floating point exceptions work correctly.

See also:

Win32 Q&A, MSJ July 1999
http://www.microsoft.com/msj/0799/win32/win320799.htm

Win32 Q&A, MSJ October 1999
http://www.microsoft.com/msj/1099/win32/win321099.htm

Here are two macro overlays to facilatate this usage:

Note:

The thread that uses CreateThreadEx to launch new threads should
also dispose of any generated thread handle using CloseHandle.

HANDLE MyThread = CreateThreadEx(...);
...
CloseHandle(MyThread);

--------------------------------------------------------------------------- */
typedef unsigned (__stdcall *StartAddressT)(void*);

#define CreateThreadEx(
lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId ) ( (HANDLE) _beginthreadex( (void *) (lpThreadAttributes), (unsigned int) (dwStackSize), (StartAddressT) (lpStartAddress), (void *) (lpParameter), (unsigned int) (dwCreationFlags), (unsigned int *) (lpThreadId) ) )


#define ExitThreadEx(dwExitCode) _endthreadex((unsigned int)dwExitCode)

#endif /* CREATETHREADEX_H_ */



Edit: for some reason the source tags are mangling the macro. Viewing the page source indicates the macro remains in place, albeit damaged. Given the overwhelming amount of code this macro is moot anyway. However, those urls are worth reviewing.



"Beautiful maiden," answered Candide, "when a man is in love, is jealous, and has been flogged by the Inquisition, he becomes lost to all reflection."


[edited by - lessbread on December 6, 2002 4:59:35 PM]

Share this post


Link to post
Share on other sites

  
// The class


class ThreadedClass
{
public:
ThreadedClass();
static DWORD WINAPI threadInit( void * tc_arg );
void someMethod();
};
 
DWORD WINAPI ThreadedClass::threadInit( void * tc_arg )
{
ThreadedClass * tc = reinterpret_cast<ThreadedClass *>(tc_arg);
tc->someMethod(); // function dispatch


}
 
// in some function somewhere


{
...
ThreadedClass tc;
DWORD id;
HANDLE hThread = CreateThread( NULL, 0, ThreadedClass::threadInit, &tc, 0, &id );
...
}

Share this post


Link to post
Share on other sites
thanks for the code supply - it would be morning over there till i managed it on my own - it i ever would have.

thank you

Share this post


Link to post
Share on other sites
I would do something like the -- untested -- code that follows:

  
#include <iostream>
#include <memory>
#define NOMINMAX
#include <windows.h>

struct Foo
{
DWORD ThreadProc1(void*)
{
std::cout << "Inside Foo::ThreadProc1" << std::endl;
return 0;
}
DWORD ThreadProc2(void*)
{
std::cout << "Inside Foo::ThreadProc2" << std::endl;
return 0;
}
};

struct Bar
{
DWORD ThreadProc(void*)
{
std::cout << "Inside Bar::ThreadProc1" << std::endl;
return 0;
}
};

template <typename T>
struct ThreadInfo
{
typedef T class_type;
typedef DWORD(T::* function_type)(void*);

T* obj;
function_type function;
void* data;
ThreadInfo(class_type* f, function_type fp, void* d) : obj(f), function(fp), data(d) {}
};

template <typename T>
DWORD WINAPI ThreadDispatch(void* data)
{
std::auto_ptr<ThreadInfo<T> > ti(static_cast<ThreadInfo<T>*>(data));
return ((ti->obj)->*(ti->function))(ti->data);
}

template <typename T>
HANDLE CreateThread(SECURITY_ATTRIBUTES* sa, SIZE_T stackSize, T* object, DWORD(T::* threadRoutine)(void*), void* parameters, DWORD creationFlags, DWORD* tid)
{
std::auto_ptr<ThreadInfo<T> > ti(new ThreadInfo<T>(object, threadRoutine, parameters));
HANDLE rv = CreateThread(sa, stackSize, ThreadDispatch<T>, static_cast<void*>(ti.get()), creationFlags, tid);
if(NULL != rv)
{
ti.release();
}
return rv;
}

// In practice, you''ll normally not need all the parameters, so a convenience overload is provided.

template <typename T>
HANDLE CreateThread(T* object, DWORD(T::* threadRoutine)(void*), void* parameters)
{
return CreateThread(NULL, 0, object, threadRoutine, parameters, 0, NULL);
}

int main()
{
using namespace std;
auto_ptr<Foo> foo(new Foo);
HANDLE thread = CreateThread(foo.get(), &Foo::ThreadProc1, NULL);
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
auto_ptr<Bar> bar(new Bar);
thread = CreateThread(bar.get(), &Bar::ThreadProc, NULL);
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
}


Share this post


Link to post
Share on other sites
If you''re a generic kinda guy, this helper-class lets you turn any class method into a thread.


  
template <typename ParentClass>
class Thread
{
public:
Thread() : m_hThread(INVALID_HANDLE_VALUE), m_dwID(0), m_pParentClass(0)
{
}

~Thread()
{
if(IsValid())
{
if(!IsTerminated())
{
ASSERTMSG(0, "Thread object being destroyed prior to thread termination!\n");
Exit();
}
CloseHandle(m_hThread);
m_hThread=INVALID_HANDLE_VALUE;
}
}

HANDLE handle(){return m_hThread;}

typedef UINT (ParentClass::*MethodProc)(void);
typedef Event<false, false> tyEvent;
tyEvent m_evExit;

bool Create(ParentClass* pThis, MethodProc pThreadMethod, const char* const name = 0)
{
ASSERTMSG(INVALID_HANDLE_VALUE==m_hThread, "Don''t call Thread<>::Create without calling Close!");
if(INVALID_HANDLE_VALUE!=m_hThread)
return false;

m_evExit.Reset();
m_pParentClass = pThis;
m_pMethodProc = pThreadMethod;
//m_hThread = (HANDLE)_beginthreadex(NULL, 0, &DefaultProc, this, 0, (UINT*)&m_dwID);

m_hThread = CreateThread(NULL, NULL, &DefaultProc, this, 0, &m_dwID);

if( (0==m_hThread) || (INVALID_HANDLE_VALUE==m_hThread) )
return false;
else
return true;
}

bool Exit(DWORD dwTime_ms=5000)
{
Lock<> AutoLock(m_csLock);

if(IsValid())
{
m_evExit.Signal();
if(WaitForTermination(dwTime_ms))
return true;
else
{
char szMsg[128];
strcpy(szMsg, "* ");
//strcpy(&szMsg[strlen(szMsg)], typeid(*this).name());

strcpy(&szMsg[strlen(szMsg)], "Thread<> ");
strcpy(&szMsg[strlen(szMsg)], " forcefully terminated\n");
Debug::Console.Out(szMsg);
return Terminate();
}
}
else
return true;
}

bool Close()
{
assert(INVALID_HANDLE_VALUE!=m_hThread);
ASSERTMSG(IsTerminated(), "Terminate the thread prior to closing it''s handle!");
if(!IsTerminated())
Exit(5000);
if(CloseHandle(m_hThread))
{
m_hThread=INVALID_HANDLE_VALUE;
return true;
}
else
return false;
}

bool IsValid() {return(INVALID_HANDLE_VALUE!=m_hThread);}
bool IsTerminated() {return (WAIT_OBJECT_0==WaitForSingleObject(m_hThread, 0));}
bool IsRunning() {return (WAIT_TIMEOUT==WaitForSingleObject(m_hThread, 0));}

BOOL Suspend()
{
assert(INVALID_HANDLE_VALUE!=m_hThread);
return SuspendThread(m_hThread);
}

BOOL Resume()
{
assert(INVALID_HANDLE_VALUE!=m_hThread);
return ResumeThread(m_hThread);
}

enum ePriority
{
TimeCritical = THREAD_PRIORITY_TIME_CRITICAL,
Highest = THREAD_PRIORITY_HIGHEST,
AboveNormal = THREAD_PRIORITY_ABOVE_NORMAL,
Normal = THREAD_PRIORITY_NORMAL,
BelowNormal = THREAD_PRIORITY_BELOW_NORMAL,
Lowest = THREAD_PRIORITY_LOWEST,
Idle = THREAD_PRIORITY_IDLE
};

BOOL SetPriority(ePriority priority)
{
assert(INVALID_HANDLE_VALUE!=m_hThread);
return SetThreadPriority(m_hThread, priority);
}

bool WaitForTermination(DWORD dwTime_ms=INFINITE)
{
assert(INVALID_HANDLE_VALUE!=m_hThread);
return(WAIT_OBJECT_0==WaitForSingleObject(m_hThread, dwTime_ms));
}

protected:
static unsigned long __stdcall DefaultProc(void* pv)
{
assert(pv);
Sleep(10);
return reinterpret_cast<Thread*>(pv)->Run();
}
UINT Run()
{
try
{
assert(m_pParentClass);
assert(this);
assert(m_pMethodProc);
if(m_pParentClass)
{
UINT x = (m_pParentClass->*m_pMethodProc)();
return x;
}
}
catch(...)
{
ASSERTMSG(0, "Thread threw an uncaught exception");
throw;
}

return -3;
}
MethodProc m_pMethodProc;
ParentClass* m_pParentClass;

bool Terminate()
{
Lock<CriticalSection> AutoLock(m_csLock);

if(INVALID_HANDLE_VALUE!=m_hThread)
if(TerminateThread(m_hThread, -42))
return true;
else
return false;
else
return true;
}

protected:
volatile HANDLE m_hThread;
DWORD m_dwID;
CriticalSection m_csLock;
};




Example use:

struct SomeClass
{
Thread thread;

UINT Run();

void Initialize()
{
BOOL bResult = this->thread.Create(this, Run);
}
void Shutdown()
{
this->thread.Exit();
}
};

UINT SomeClass::Run()
{
while(!this->thread.m_evExit.WaitFor(sleepTime_ms))
{
//Thread code goes here
}
}


A single class can have more than one type of thread this way.

Share this post


Link to post
Share on other sites
now it is running and everything is fine.

am I right if I think I just have to give an other class in that last pointer to run a function from that class...

I just want to write some code down to make it threaded (processing input) i already coded it i an class and if I could now make it run with just switching the pointer/function that is called it would be greate.

anyway thank you - you guy''s realy help me a lot!
I hope I can help people with what i have learned today too someday!

Share this post


Link to post
Share on other sites

  • Advertisement