Click here to Skip to main content
15,885,278 members
Articles / Desktop Programming / MFC
Article

Worker Class

Rate me:
Please Sign up or sign in to vote.
2.20/5 (5 votes)
16 Jan 2009GPL33 min read 32.1K   285   19   8
An article showing how a WokerClass object can simplify multi-threaded operations.

Introduction

The WorkerClass is an extremely simple MFC class to help you with multi-threading. Any object you want to do work that needs to be in its own thread derives from 'WorkerClass'. Implement the DoWork function to carry out the long process - and then call Start/Stop/Pause on the object to carry out the work.

Because of C++'s ability to handle multiple inheritence this means you can make a CDialog a worker class, and any CObject a worker class - in fact, any class at all can be a WorkerClass.

Why?

The DoWork function is called in a seperate thread, but it is a member of the class. This means your threaded function can access all of the classes member variables and functions and so on. A threaded process function generally has to be called as a global or static function - meaning this sort of data has to be passed to it. See what I mean in the example below.

The Example Application

I create a dialog based MFC application - and change the dialog definition as such:

C++
// WorkerClassExampleDlg.h : header file
//

#pragma once

#include "WorkerClass.h"
#include "afxwin.h"

Important change number one - include the WorkerClass header! Don't forget to add the source file to the project too!

C++
// CWorkerClassExampleDlg dialog
class CWorkerClassExampleDlg : public CDialog, 
public WorkerClass	//	This makes the dialog a worker class.
{
// Construction
public:
	CWorkerClassExampleDlg(CWnd* pParent = NULL);	// standard constructor

Important change number two - the dialog inherits from CDialog AND WorkerClass! This is crucial! Why no hungarian notation for WorkerClass (i.e. CWorkerClass?). Well the class is actually not reliant on MFC. I generally only use the 'C' prefix on MFC classes. WorkerClass will work fine in plain Win32 applications. The only other important addition is below:

C++
//  The most important part of the worker class - the DoWork function.
virtual void DoWork();

This function must be overriden in the CDialog. It's the function that does the threaded work.

The only other change we need to make at this stage is to add the implementation:

C++
void CWorkerClassExampleDlg::DoWork()
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	//	As long as we're not being told to stop, we can do some pretend work!
	while(GetStatus() != Stopping)
	{
		//	Blah blah blah - do some long winded work!

		//	Wait.
		Sleep(100);
	}
}

Typically the AFX_MANAGE_STATE macro isn't needed. However, it's safer to put it in, it attempts to make Window and Control handles share across threads a little bit better.

Just carry out the long operation in this function - that's all there is too it! One thing you can also do is regularly check to see if the WorkerClass has been asked to stop, by calling:

C++
if(GetStatus() == Stopping)

When you call 'Stop' on the Worker Class the status is set to 'Stopping'. This is politely asking the work to stop if possible. In the example above we just keep looping until we're told to stop.

You don't NEED to do this - and you can forcibly terminate the work by calling 'Terminate', but it's slightly more graceful.

Controlling Work

Let's say I have a 'Start Work' button on the dialog - here's what I can do:

C++
void CWorkerClassExampleDlg::OnBnClickedButtonStart()
{
	//	Start the thread.
	Start();

easy. How do I stop the thread? Call Stop(). Toggle pause on or off by calling Pause().

Members

Here's the functions you need to know about!

Start()

Start the WorkerClass.

Stop()

Ask the WorkerClass to stop. This function will not return until the thread has genuinely stopped - so depending on the work and how well the function has been written this could possibly take some time.

Terminate()

Force the WorkerClass to stop. This function kills the thread and returns immediately.

Pause()

Pauses the execution of the thread if working, and unpauses it if it's not working.

Status GetStatus() const

Get's the current status of the Worker Class:

Stopped - The worker class isn't working. You can start it.
Stopping - The worker class has been asked to stop.
Paused - The worker class has been suspended - but it can be unpaused or terminated.
Working - The worker class is working. You can stop, terminate or pause it.

And The Rest

Leave comments if you have any questions or problems! This class isn't heavyweight - but it's perfect for quickly multithreading work. Enjoy!

History

  • 14th January 2009 - Wrote the first revision of the article.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)



Comments and Discussions

 
GeneralMy vote of 1 Pin
Panic2k321-Aug-10 15:28
Panic2k321-Aug-10 15:28 
GeneralSome Criticism: Beginners Please Read This Pin
Mike O'Neill22-Jan-09 5:34
Mike O'Neill22-Jan-09 5:34 
GeneralThe design of WorkerClass class contradict MSDN! [modified] Pin
Victor Nijegorodov22-Jan-09 3:54
Victor Nijegorodov22-Jan-09 3:54 
QuestionBusy waiting???? Pin
User 433002821-Jan-09 1:07
User 433002821-Jan-09 1:07 
GeneralMy vote of 1 Pin
wa18-Jan-09 23:54
wa18-Jan-09 23:54 
GeneralRe: My vote of 1 Pin
Dave Kerr19-Jan-09 6:03
Dave Kerr19-Jan-09 6:03 
GeneralKeep GUI alive Pin
Davide Zaccanti18-Jan-09 23:22
Davide Zaccanti18-Jan-09 23:22 
Can be used to keep window refresh alive and / or animation ( ie. during execution of external CPU intensive process) ?

Can DoWork() host a pump message cicle ?

Thank you.
GeneralRe: Keep GUI alive Pin
Dave Kerr19-Jan-09 5:54
Dave Kerr19-Jan-09 5:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.