Generic Thread Object
his code implements a generic thread object. I have derived from this class to produce thread pools in multithreaded servers.
This interface assumes that the user is interested in working at the thread/process level of detail. Abstractions could be used if necessary.
Note that this is a console application [uses fprintf(stderr,...)] - the message mechanism could be easily abstracted but doing so would have violated the goal of simplicity, until such time as that abstraction is necessary.
Compatibility/System Requirements
This code was compiled with VC7 on Windows 2000 and Windows XP systems.
Code
// Thread Tools
// Copyright (c) 2004, 2005 Robin Eric Fredericksen
// -- All rights reserved.
//==================================================
// The interfaces
//==================================================
//==================================================
// use this for auto scope protection for threading
//==================================================
class CScopeProtector
{
protected:
CRITICAL_SECTION & m_roCS;
public:
CScopeProtector(CRITICAL_SECTION & _roCS)
: m_roCS(_roCS)
{
EnterCriticalSection(&m_roCS);
}
virtual ~CScopeProtector()
{
LeaveCriticalSection(&m_roCS);
}
};
//==================================================
class CTaskThread
{
public:
enum
{
INITIALIZED,
RELEASED,
WAITING,
ASSIGNED,
RUNNING,
DEAD
} threadstate;
protected:
// debugging
HANDLE m_hThreadHandle;
DWORD m_dwThreadID;
// for blocking and waiting for work
HANDLE m_hGateKeeper;
// for keeping track of where we are, for others to query
DWORD m_dwThreadState;
public:
CTaskThread(void);
virtual ~CTaskThread();
DWORD GetThreadState(void) { return(m_dwThreadState); }
bool InitSuccess(void) { return( m_hThreadHandle && m_hGateKeeper ); }
// override this function to implement your work
virtual DWORD VirtualCallbackFunction(void);
// this is the function that will be spawned
static int __cdecl TaskThread( void * _pvMyThisPointer );
typedef void( __cdecl *pFNStartAddress )( void * );
HANDLE StartThread(void);
// opens gate for thread to try to do work
void ReleaseThread(void);
};
//==================================================
// The implementation
//==================================================
#include <process.h>
//==================================================
CTaskThread::CTaskThread(void)
{
m_dwThreadID = 0;
m_hThreadHandle = 0;
m_hGateKeeper = 0;
m_dwThreadState = DEAD;
m_hGateKeeper = CreateEvent(
NULL, // default security
TRUE, // manually reset
FALSE, // start nonsignaled
NULL // not named
);
if( m_hGateKeeper )
{
StartThread();
}
}
//==================================================
CTaskThread::~CTaskThread()
{
if( m_hGateKeeper ) CloseHandle(m_hGateKeeper);
m_dwThreadState = DEAD;
}
//==================================================
void CTaskThread::ReleaseThread(void)
{
m_dwThreadState = RELEASED;
SetEvent(m_hGateKeeper);
}
//==================================================
HANDLE CTaskThread::StartThread(void)
{
// we are required to have a function with a particular signature
// here, so we us an intermediary so we maintain our class-yness. ;)
m_hThreadHandle = (HANDLE)// returns threadID
_beginthread(
(pFNStartAddress)TaskThread,
NULL, // default thread stack
this
);
return( m_hThreadHandle );
}
//==================================================
// this is the function that will be spawned
//==================================================
int __cdecl CTaskThread::TaskThread( void * _pvMyThisPointer )
{
if( !_pvMyThisPointer ) return(-1);
CTaskThread * pMe = (CTaskThread*)_pvMyThisPointer;
pMe->m_dwThreadID = GetCurrentThreadId();
DWORD dwResult = 0;
// go to a waiting state
pMe->m_dwThreadState = WAITING;
while(WAIT_OBJECT_0 == WaitForSingleObject(pMe->m_hGateKeeper, INFINITE) )
{
// indicate that we are running
pMe->m_dwThreadState = RUNNING;
// call the virtual function to do the work
dwResult = pMe->VirtualCallbackFunction();
// go back to a waiting state
ResetEvent(pMe->m_hGateKeeper);
pMe->m_dwThreadState = WAITING;
}
pMe->m_dwThreadState = DEAD;
return(dwResult);
}
//==================================================
DWORD CTaskThread::VirtualCallbackFunction(void)
{
// this is the function to be over-ridden
// could make it pure virtual...
Sleep(1000);
return(0);
};