235 lines
5.9 KiB
C++
235 lines
5.9 KiB
C++
#ifndef __THREAD_H__
|
|
#define __THREAD_H__
|
|
|
|
class CThread
|
|
{
|
|
public:
|
|
/*
|
|
* Info: Default Constructor
|
|
*/
|
|
CThread()
|
|
{
|
|
m_pThreadFunc = CThread::EntryPoint; // Can call Detach() also.
|
|
}
|
|
|
|
/*
|
|
* Info: Plug Constructor
|
|
*
|
|
* Use this to migrate/port existing worker threads to objects immediately
|
|
* Although you lose the benefits of ThreadCTOR and ThreadDTOR.
|
|
*/
|
|
CThread(LPTHREAD_START_ROUTINE lpExternalRoutine)
|
|
{
|
|
Thread_Attach(lpExternalRoutine);
|
|
}
|
|
|
|
/*
|
|
* Info: Default Destructor
|
|
*
|
|
* I think it is wise to destroy the thread even if it is running,
|
|
* when the main thread reaches here.
|
|
*/
|
|
~CThread()
|
|
{
|
|
if ( m_ThreadCtx.m_hThread )
|
|
Thread_Stop(true);
|
|
}
|
|
/*
|
|
* Info: Starts the thread.
|
|
*
|
|
* This function starts the thread pointed by m_pThreadFunc with default attributes
|
|
*/
|
|
DWORD Thread_Start( void* arg = NULL )
|
|
{
|
|
m_ThreadCtx.m_bThreadRun = TRUE;
|
|
|
|
m_ThreadCtx.m_pUserData = arg;
|
|
m_ThreadCtx.m_hThread = CreateThread(NULL, 0, m_pThreadFunc, this, 0, &m_ThreadCtx.m_dwTID);
|
|
m_ThreadCtx.m_dwExitCode = (DWORD)-1;
|
|
|
|
return GetLastError();
|
|
}
|
|
|
|
/*
|
|
* Info: Stops the thread.
|
|
*
|
|
* This function stops the current thread.
|
|
* We can force kill a thread which results in a TerminateThread.
|
|
*/
|
|
DWORD Thread_Stop ( bool bForceKill = false )
|
|
{
|
|
m_ThreadCtx.m_bThreadRun = FALSE;
|
|
|
|
if ( m_ThreadCtx.m_hThread )
|
|
{
|
|
GetExitCodeThread(m_ThreadCtx.m_hThread, &m_ThreadCtx.m_dwExitCode);
|
|
|
|
if ( m_ThreadCtx.m_dwExitCode == STILL_ACTIVE && bForceKill )
|
|
TerminateThread(m_ThreadCtx.m_hThread, DWORD(-1));
|
|
else
|
|
{
|
|
DWORD dwRet = ::WaitForSingleObject( m_ThreadCtx.m_hCloseEvent, 1000 );
|
|
if( dwRet != WAIT_OBJECT_0 )
|
|
OutputDebugString( "Thread_Stop : Wait failed !\n" );
|
|
}
|
|
|
|
m_ThreadCtx.m_hThread = NULL;
|
|
}
|
|
|
|
return m_ThreadCtx.m_dwExitCode;
|
|
}
|
|
|
|
|
|
DWORD Thread_Suspend()
|
|
{
|
|
return ::SuspendThread(m_ThreadCtx.m_hThread);
|
|
}
|
|
|
|
DWORD Thread_Resume()
|
|
{
|
|
return ::ResumeThread(m_ThreadCtx.m_hThread);
|
|
}
|
|
|
|
BOOL Thread_SetPriority( int nPriority=THREAD_PRIORITY_NORMAL )
|
|
{
|
|
return ::SetThreadPriority(m_ThreadCtx.m_hThread, nPriority );
|
|
}
|
|
|
|
int Thread_GetPriority()
|
|
{
|
|
return ::GetThreadPriority(m_ThreadCtx.m_hThread);
|
|
}
|
|
|
|
/*
|
|
* Info: Starts the thread.
|
|
*
|
|
* This function starts the thread pointed by m_pThreadFunc with default attributes
|
|
*/
|
|
DWORD Thread_GetExitCode() const
|
|
{
|
|
if ( m_ThreadCtx.m_hThread )
|
|
GetExitCodeThread(m_ThreadCtx.m_hThread, (LPDWORD)&m_ThreadCtx.m_dwExitCode);
|
|
return m_ThreadCtx.m_dwExitCode;
|
|
}
|
|
|
|
/*
|
|
* Info: Attaches a Thread Function
|
|
*
|
|
* Used primarily for porting but can serve in developing generic thread objects
|
|
*/
|
|
void Thread_Attach( LPTHREAD_START_ROUTINE lpThreadFunc ){
|
|
m_pThreadFunc = lpThreadFunc;
|
|
}
|
|
|
|
/*
|
|
* Info: Detaches the Attached Thread Function
|
|
*
|
|
* Detaches the Attached Thread Function, If any.
|
|
* by resetting the thread function pointer to EntryPoint1
|
|
*/
|
|
void Thread_Detach( void ){
|
|
m_pThreadFunc = CThread::EntryPoint;
|
|
}
|
|
|
|
protected:
|
|
|
|
/*
|
|
* Info: DONT override this method.
|
|
*
|
|
* This function is like a standard template.
|
|
* Override if you are sure of what you are doing.
|
|
*/
|
|
static DWORD WINAPI EntryPoint( LPVOID pArg )
|
|
{
|
|
CThread *pParent = reinterpret_cast<CThread*>(pArg);
|
|
|
|
pParent->ThreadCtor();
|
|
|
|
pParent->Run( pParent->m_ThreadCtx.m_pUserData );
|
|
|
|
pParent->ThreadDtor();
|
|
|
|
return STILL_ACTIVE;
|
|
}
|
|
|
|
/*
|
|
* Info: Override this method.
|
|
*
|
|
* This function should contain the body/code of your thread.
|
|
* Notice the signature is similar to that of any worker thread function
|
|
* except for the calling convention.
|
|
*/
|
|
virtual DWORD Run( LPVOID /* arg */ )
|
|
{ return m_ThreadCtx.m_dwExitCode; }
|
|
|
|
/*
|
|
* Info: Constructor-like function.
|
|
*
|
|
* Will be called by EntryPoint before executing the thread body.
|
|
* Override this function to provide your extra initialization.
|
|
*
|
|
* NOTE: do not confuse it with the classes constructor
|
|
*/
|
|
virtual void ThreadCtor(){ TRACE("constructor...\n"); }
|
|
|
|
/*
|
|
* Info: Destructor-like function.
|
|
*
|
|
* Will be called by EntryPoint after executing the thread body.
|
|
* Override this function to provide your extra destruction.
|
|
*
|
|
* NOTE: do not confuse it with the classes constructor
|
|
*/
|
|
virtual void ThreadDtor(){ TRACE("destructor...\n"); }
|
|
|
|
private:
|
|
/*
|
|
* Info: Thread Context Inner Class
|
|
*
|
|
* Every thread object needs to be associated with a set of values.
|
|
* like UserData Pointer, Handle, Thread ID etc.
|
|
*
|
|
* NOTE: This class can be enhanced to varying functionalities
|
|
* eg.,
|
|
* * Members to hold StackSize
|
|
* * SECURITY_ATTRIBUTES member.
|
|
*/
|
|
class CThreadContext
|
|
{
|
|
public:
|
|
CThreadContext(){
|
|
memset(this, 0, sizeof(this));
|
|
m_hCloseEvent = ::CreateEvent( NULL, FALSE, FALSE, NULL );
|
|
m_bThreadRun = FALSE;
|
|
}
|
|
~CThreadContext(){
|
|
::CloseHandle( m_hCloseEvent );
|
|
}
|
|
|
|
/*
|
|
* Attributes Section
|
|
*/
|
|
public:
|
|
HANDLE m_hThread; // The Thread Handle
|
|
DWORD m_dwTID; // The Thread ID
|
|
LPVOID m_pUserData; // The user data pointer
|
|
LPVOID m_pParent; // The this pointer of the parent CThread object
|
|
DWORD m_dwExitCode; // The Exit Code of the thread
|
|
HANDLE m_hCloseEvent; // Thread close check event.
|
|
BOOL m_bThreadRun; // Thread exit condition.
|
|
};
|
|
|
|
/*
|
|
* Attributes Section
|
|
*/
|
|
public:
|
|
/*
|
|
* Info: Members of CThread
|
|
*/
|
|
CThreadContext m_ThreadCtx; // The Thread Context member
|
|
protected:
|
|
LPTHREAD_START_ROUTINE m_pThreadFunc; // The Worker Thread Function Pointer
|
|
};
|
|
|
|
#endif //__THREAD_H__
|