Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

A Simple Worker Thread Class

5.00/5 (6 votes)
29 Mar 2019CPOL2 min read 12.2K  
This is a simple worker thread class that allows when to use a member function as the thread function.

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:

C++
//
// WorkerThread.h - a very simple worker thread class.
//
// This class has a pure virtual method that is called by the thread function.
// Derived classes must implement this method to enable instantiation.
// The thread function is invoked with the this pointer has the argument.
// This allows it to call all methods and access all members of the derived class.
//

class WorkerThread
{
public :
	WorkerThread()	{}

	virtual ~WorkerThread()			{ CloseHandle( m_handle ); }

	bool Create( bool suspend = true )
	{
		m_handle = CreateThread( 0, 0,			// security attributes and stack size
								ThreadFunction,
								this,			// argument to thread function
								suspend ? CREATE_SUSPENDED : 0,
								&m_tid );
		return m_handle;
	}

	void Resume()                   { ResumeThread( m_handle ); }

    // wait for the thread to terminate - returns true if terminate flag is set

	bool Wait( int waitTime )
	{
         WaitForSingleObject( m_handle, waitTime );
         return m_Terminated;
    }

	// this method MUST be implemented by derivations

	virtual DWORD ThreadMethod() = 0;

	// static thread function that calls the virtual method supplied by the derivation

	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 };				// thread id
};

Here is a sample of a derivation.

C++
class MyWorkerThread : public WorkerThread
{
public:
	MyWorkerThread( int index )
	    : WorkerThread()
	    , m_Index( index )
	{
	}

	virtual DWORD ThreadMethod()    // this is the method used for the thread
	{
		_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.

C++
void DoThreadTest()
{
	MyWorkerThread wt( 1 );
	wt.Create( true );           // create the thread in a suspended state
	_tprintf( _T( "thread was created - now resuming\n" ) );
	wt.Resume();                 // resume thread execution
	bool rv = wt.Wait( 5000 );   // wait for thread termination

	_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. Threads 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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)