Introduction
This tip presents a very simple worker thread class that allows one to use a class method as the thread
function.
Background
Useful background for this information is familiarity with threads and C++.
Using the Code
My motivation for writing this was how often I have seen the question, "how can I use a method of my class for my thread function?" asked. The simple answer is no, you can't, directly. This class provides a simple way to actually do that. It is not quite an out-of-the-box solution because it requires one to derive a class from it but it is about as close as one can get.
This is a basic, header-only class. You only have to include the header file, derive your own class, and you are ready to go. Here it is:
class WorkerThread
{
public :
WorkerThread() {}
virtual ~WorkerThread() { CloseHandle( m_handle ); }
bool Create( bool suspend = true )
{
m_handle = CreateThread( 0, 0, ThreadFunction,
this, suspend ? CREATE_SUSPENDED : 0,
&m_tid );
return m_handle;
}
void Resume() { ResumeThread( m_handle ); }
bool Wait( int waitTime )
{
WaitForSingleObject( m_handle, waitTime );
return m_Terminated;
}
virtual DWORD ThreadMethod() = 0;
static DWORD WINAPI ThreadFunction( PVOID arg )
{
auto pwt = (WorkerThread *) arg;
DWORD rv = pwt->ThreadMethod();
pwt->m_Terminated = true;
return rv;
}
protected :
bool m_Terminated { false };
HANDLE m_handle { NULL };
DWORD m_tid { 0 }; };
Here is a sample of a derivation.
class MyWorkerThread : public WorkerThread
{
public:
MyWorkerThread( int index )
: WorkerThread()
, m_Index( index )
{
}
virtual DWORD ThreadMethod() {
_tprintf( _T( "this is thread %d - id %04X\n" ), m_Index, m_tid );
Sleep( 1000 );
_tprintf( _T( "thread %d has left the building\n" ), m_Index );
return m_Index;
}
int m_Index { 0 };
};
Here is a sample using the derived class.
void DoThreadTest()
{
MyWorkerThread wt( 1 );
wt.Create( true ); _tprintf( _T( "thread was created - now resuming\n" ) );
wt.Resume(); bool rv = wt.Wait( 5000 );
_tprintf( _T( "returned from wait - termination flag is %s\n" ),
rv ? _T( "true" ) : _T( "false" ) );
}
Points of Interest
As you can see, this class makes it very easy to use a class method as a thread
function. Thread
s can be created in a suspended state and subsequently resumed or they can be created and executed immediately.
The way this works is a static
method of the class is the thread
function. This is allowed because static
members do not have an implied this
pointer. When the thread
is created, a pointer to the object is passed to the thread
function and then a pure virtual
method of the class is called by the thread
function. The method is "pure virtual
" because it is undefined in the base class which means the WorkerThread
class cannot be instantiated. A derived class is required to implement this virtual
method for it to be instantiated. In effect, what is happening is the this
pointer is passed explicitly to the static thread
function instead of implicitly as with non-static
class methods.