Source code for C_Thread
Download
The source files for this module are listed below. You can also download the module C_Thread as a zip archive; this archive contains all the source files and documentation.
Description
CThread provides easy multi-threading support to your application, where each thread is maintained by a separate object.
Information
To start using multithreading, derive your class from CThread. Then overload the Action routine; all processing that has to be done in your worker thread should be placed in this routine. You can return the result of your Action as a void*, so passing everything up to 4-byte sized return values (the size of a void*) is effortless. When you however want to return a pointer to something, make sure that someone will deallocate the structure referenced to. The result of the action can be called from each thread via the Result method.
If you need to do some intitialization or destruction in your thread, overload the ThreadInit and/or the ThreadEnd routines. These will be guaranteed to run before and after your Action code.
To actually use the threading class, create an object of your CThread derived class and call it's Start method. The Start method will return immediately, and soon after the thread object's Action routine will start running on a separate thread.
Since the thread object belongs in two threads (the thread controlling part and the worker part), the object may not destruct the originating thread e.g. when it goes out of scope, since the thread object will be needed in the worker as well.
The option of where to destroy the thread object can be specified as a parameter to the Start method. If you choose to let the object self destruct, the object will be deleted as a last step in the thread's lifetime (after the ThreadEnd method has run).
Three indicators are available to get the current state of the thread.
- The Start method returns whether the thread could be started at all.
- The method State will tell you what state the thread is in at the current moment. Since there is a little startup delay before the Action method kicks in, you should check the State to make sure the Action routine is running at all. The same goes for the shut-down delay.
- The IsBusy method will tell you when the thread is busy (starting up, running or finishding).
To get thread-specific details about your newly created worker thread object, you can use the GetID and GetHandle methods. The handle that GetHandle returns will be closed when the thread object destructs.
Notes / todo's
- To use common resources with multiple threads, make sure you have some access locking for it. Use our CLock and related classes to do just this.
- Make sure you have multi-threading enabled in your project settings and/or link with the multi-threaded libraries, if applicable!
Files
Each file belonging to this source code module is listed below.
Thread.h
/*******************************************************************************
Version: 2
Author: Carl Colijn, TwoLogs
Contact: c.colijn@twologs.com
Source: http://www.twologs.com/sourcecode
This code is freely distributable, as long as this comment remains intact.
If you find this source useful, you may use this code in your own projects
free of charge, but some acknowledgement to the author of this code is always
appreciated :)
The source is however distributed 'as is' without waranty and/or support, and
may not be fit for each and every application. Use it at your own discretion
and at your own risk.
The source already has undergone testing. This doesn't mean however that all
bugs are removed from this piece of code. If you find one of them, please
contact me about it. I can however not guarantee when and if the bug will be
fixed.
More information about this module can be found in the accompanying HTML file.
*******************************************************************************/
#ifndef INCLUDE_TWOLOGS_COMMON_THREAD_H
#define INCLUDE_TWOLOGS_COMMON_THREAD_H
#include <windows.h>
// Phase of the thread execution
enum EThreadState {
g_ceThreadStateIdle,
g_ceThreadStateStarting,
g_ceThreadStateBusy,
g_ceThreadStateFinishing,
g_ceThreadStateError
};
class CThread {
public:
// Con- & destructor
CThread();
virtual ~CThread();
// Starts up the thread. If you specify the object should auto-
// destruct, it will be deleted at the end of the thread's work
bool Start(bool bAutoDestruct);
// Returns the state the thread is in
EThreadState State() const;
// Returns whether the thread is still busy
bool IsBusy() const;
// Returns the result
void* Result() const;
// Gets the thread's ID
unsigned int GetID() const;
// Gets the thread's handle
HANDLE GetHandle() const;
protected:
// Handle to the thread
HANDLE m_hThread;
// The thread's ID
unsigned int m_nThreadID;
// The result of the thread
void* m_puResult;
// Thread initialization and destruction
virtual bool ThreadInit();
virtual void ThreadEnd();
// Action to perform
virtual void* Action();
private:
// Our current state
EThreadState m_eState;
// Whether we should auto-destruct
bool m_bAutoDestruct;
// Thread startpoint helper function
static unsigned int __stdcall StartThread(void* puVoidThread);
};
#endif // INCLUDE_TWOLOGS_COMMON_THREAD_H
Thread.cpp
/*******************************************************************************
Version: 2
Author: Carl Colijn, TwoLogs
Contact: c.colijn@twologs.com
Source: http://www.twologs.com/sourcecode
This code is freely distributable, as long as this comment remains intact.
If you find this source useful, you may use this code in your own projects
free of charge, but some acknowledgement to the author of this code is always
appreciated :)
The source is however distributed 'as is' without waranty and/or support, and
may not be fit for each and every application. Use it at your own discretion
and at your own risk.
The source already has undergone testing. This doesn't mean however that all
bugs are removed from this piece of code. If you find one of them, please
contact me about it. I can however not guarantee when and if the bug will be
fixed.
More information about this module can be found in the accompanying HTML file.
*******************************************************************************/
#include "Thread.h"
#include <process.h>
// Constructor
CThread::CThread() {
// Init our state
m_puResult = NULL;
m_eState = g_ceThreadStateIdle;
m_bAutoDestruct = false;
m_hThread = NULL;
m_nThreadID = 0;
}
// Destructor
CThread::~CThread() {
// Look if we have a thread handle
if (m_hThread != NULL)
// Yes -> close the handle
CloseHandle(m_hThread);
}
// Starts up the thread. If you specify the object should auto-
// destruct, it will be deleted at the end of the thread's work
bool CThread::Start(bool bAutoDestruct) {
// Look if we have already started
bool bSuccess = false;
if (!IsBusy()) {
// No -> try to start the new thread
m_bAutoDestruct = bAutoDestruct;
m_eState = g_ceThreadStateStarting;
m_hThread = (HANDLE)_beginthreadex(NULL, 0, StartThread, this, 0, &m_nThreadID);
bSuccess = m_hThread != NULL;
if (!bSuccess) {
m_eState = g_ceThreadStateError;
}
}
return bSuccess;
}
// Returns the state the thread is in
EThreadState CThread::State() const {
return m_eState;
}
// Returns whether the thread is still busy
bool CThread::IsBusy() const {
return m_eState != g_ceThreadStateIdle &&
m_eState != g_ceThreadStateError;
}
// Returns the result
void* CThread::Result() const {
return m_puResult;
}
// Gets the thread's ID
unsigned int CThread::GetID() const {
return m_nThreadID;
}
// Gets the thread's handle
HANDLE CThread::GetHandle() const {
return m_hThread;
}
// Thread initialization
bool CThread::ThreadInit() {
return true;
}
// Thread destruction
void CThread::ThreadEnd() {
}
// Action to perform
void* CThread::Action() {
return NULL;
}
// Thread startpoint helper function
unsigned int __stdcall CThread::StartThread(void* puVoidThread) {
// Easy try-run-and-catch-on-error for simple statements
#define TRYTOPERFORM(__what, __nErrorID) \
try { \
__what; \
} \
catch (...) { \
nError = __nErrorID; \
}
// Get the thread object to use
CThread* puThread = (CThread*)puVoidThread;
DWORD nError = 0;
// Do thread initialization
bool bProceedAfterInit = false;
TRYTOPERFORM(bProceedAfterInit = puThread->ThreadInit(), 1);
if (bProceedAfterInit) {
// Init OK -> note we've started
TRYTOPERFORM(puThread->m_eState = g_ceThreadStateBusy, 2);
// Perform the action
TRYTOPERFORM(puThread->m_puResult = puThread->Action(), 3);
// Note we're done
TRYTOPERFORM(puThread->m_eState = g_ceThreadStateFinishing, 4);
// And do thread destruct code
TRYTOPERFORM(puThread->ThreadEnd(), 5);
}
// Note the thread is done, and is safe to delete if needed
TRYTOPERFORM(puThread->m_eState = g_ceThreadStateIdle, 6);
// Look if any errors occured up till now
if (nError != 0) {
// Yes -> report this as well
TRYTOPERFORM(puThread->m_eState = g_ceThreadStateError, 7);
}
// Look if the thread should auto-destruct
bool bSelfDestruct = false;
TRYTOPERFORM(bSelfDestruct = puThread->m_bAutoDestruct, 8);
if (bSelfDestruct) {
// Yes -> kill it now
TRYTOPERFORM(delete puThread, 9);
}
// And return what happened
return nError;
}

Products
Overview
C_Thread