I wrote down the class below for general threading needs in Win32 programs.
Win32 API is written for C, and sometimes can have inconsistancies with CPP.
For instance, the third parameter of the Win32 API function CreateThread() must be a pointer to a function in the form of "DWORD WINAPI FunctionName(LPVOID lpParameter);". However, if you decide to use this API function in a CPP class you encounter a problem. When I wrote down my threading class code for the first time, couldn't compile it. The compiler gave an irrelevent error message which wasn't describing the real problem in the code. After googling and comparing with sample codes I understood what the problem was.
I learned that all C++ member functions had a hidden first parameter, which is nothing but a pointer to the class they are in. I didn't know how to deal with this hidden parameter, actually I had no idea, I was stuck. So I used sample codes I found on the net to write my own code. Every sample code has these common similarities:
1) Class method which will be passed to CreateThread() API function (in my code, it is the ThreadProc() method) is declared to be static.
2) The parameter passed to ThreadProc() is the pointer to the class itself (i.e.; the "this" pointer);
3) "this" pointer is passed to the fourth parameter of CreateThread().
My code is working if you define only one instance of the class. But it gives a runtime error if you define a second instance. I think, it has something to do with the static ThreadProc() method.
Can anyone plase answer my questions about all these confusion:
1) Why do we have to define ThreadProc() static? What does it change?
2) I didn't understand the relation between every method having a hidden first parameter "this", and the fact that we passed "this" (via the fourth parameter of CreateThread()) as the first parameter. It already had a hidden "this", and we passed a second one. It made two "this"es, didn't it? Why did we need to pass a second "this"? What is the logic behind this?
3) How should I modify my code, so that I can declare multiple instances of my class without any runtime errors?
(IDE : Visual Studio 2005 SP 1)
GenericThread.cpp#pragma once
#include <Windows.h>
class GenericThread
{
public:
GenericThread();
~GenericThread();
// Create and run the thread
HANDLE StartThread(int nPriority = 0, bool create_suspended = false, SIZE_T stack_size = 0, bool reserve_stack = false);
// This member function will run when you call StartThread()
static DWORD WINAPI ThreadProc(void * lpParameter);
// The run() method which will be called for threading
virtual void run();
// -15 : lowest; +15 : highest
void SetThreadPriority(int nPriority);
// Get currently assigned priority level
int GetThreadPriority();
// Get thread status
bool IsThreadRunning();
// Pause execution
void SuspendThread();
// Resume execution
void ResumeThread();
// Terminate execution
void TerminateThread();
// Return thread handle
HANDLE GetThreadHandle();
private:
// Handle to the thread
HANDLE m_hThread;
// The thread id assigned by Windows, there is no use for now
LPDWORD m_lpdwThreadID;
// Thread status
bool m_bRunning;
};
GenericThread.h#include "GenericThread.h"
GenericThread::GenericThread()
{
m_bExiting = false;
m_bRunning = false;
}
GenericThread::~GenericThread()
{
if (m_bRunning) CloseHandle(m_hThread);
}
HANDLE GenericThread::StartThread(int nPriority /*= 0*/, bool create_suspended /*= false*/, SIZE_T stack_size /*= 0*/, bool reserve_stack /*= false*/)
{
DWORD dwCreationFlags = 0;
if (create_suspended) dwCreationFlags |= CREATE_SUSPENDED;
if (reserve_stack) dwCreationFlags |= STACK_SIZE_PARAM_IS_A_RESERVATION;
m_hThread = CreateThread(NULL, stack_size, (LPTHREAD_START_ROUTINE) ThreadProc, (void *) this, dwCreationFlags, m_lpdwThreadID);
SetThreadPriority(nPriority);
m_bRunning = true;
return m_hThread;
}
DWORD WINAPI GenericThread::ThreadProc(void * lpThis)
{
((GenericThread *) lpThis)->run();
return 0;
}
void GenericThread::run()
{
}
void GenericThread::SetThreadPriority(int nPriority)
{
::SetThreadPriority(m_hThread, nPriority);
}
int GenericThread::GetThreadPriority()
{
return ::GetThreadPriority(m_hThread);
}
bool GenericThread::IsThreadRunning()
{
return m_bRunning;
}
void GenericThread::SuspendThread()
{
::SuspendThread(m_hThread);
}
void GenericThread::ResumeThread()
{
::ResumeThread(m_hThread);
}
void GenericThread::TerminateThread()
{
CloseHandle(m_hThread);
m_bRunning = false;
}
HANDLE GenericThread::GetThreadHandle()
{
return m_hThread;
}