A thread wrapper class






3.11/5 (4 votes)
Apr 12, 2007
1 min read

36541

748
A wrapper class of worker thread
Introduction
As a C++ programmer in Windows platform, I often use worker thread to deal with some tasks. For example I need to keep the GUI active while a computation is being performed.
But it isn't easy to implement the special synchronization feature for program beginner. To solve the problem, I write the ThreadModel class. The c
lass written in Microsoft Visual C++ is a wrapper class that can control worker thread running exactly, such as Start, Stop and Wait thread until it is ended.
How is it working?
// -----------
// ThreadModel
// ------------
class ThreadModel
{
public:
//---------------------
// functions that be used to control the thread running.
//---------------------
// start the thread
BOOL StartThread();
// stop the thread
void StopThread();
BOOL WaitThread(DWORD nTimeOut = INFINITE); // virtual function
protected:
//---------------------
// override functions
//---------------------
virtual void BeforeThread();
virtual void AfterThread();
// the thread function
virtual UINT Run() = 0;
protected:
/// Query if the the method "stop thread" has been executed.the paramater "dwDuration" is waiting time
/// if it is "0",the method will return at once.
BOOL QueryExitEvent(DWORD dwDuration = 0);
/// Query the the thread if existing
BOOL IsThreadRunning() { return (m_hThread != 0); }
private:
/// the static thread function
static UINT __stdcall __ThreadProxyProc(LPVOID pParam);
protected:
ThreadModel();
virtual ~ThreadModel();
protected:
HANDLE m_hThread;//<the handle of thread
private:
BOOL m_bLowCpuPriority; //<
HANDLE m_hEvtThreadStart; //<
HANDLE m_hEvtThreadOver; //<
HANDLE m_hEvtUserAbort; //<
};
1.StartThread
BOOL ThreadModel::StartThread()
{
if (m_hThread != NULL) return FALSE;
::ResetEvent(m_hEvtUserAbort);
::ResetEvent(m_hEvtThreadOver);
UINT nThreadID = 0;
//start the new worker thread
int nVal = _beginthreadex(NULL, 0, __ThreadProxyProc, (void *)this, 0, &nThreadID);
if(nVal <= 0)
{
return FALSE;
}
m_hThread = reinterpret_cast<HANDLE>(nVal);
if (m_bLowCpuPriority)
SetThreadPriority(m_hThread, THREAD_PRIORITY_IDLE);
// wait thread start
DWORD nWait = ::WaitForSingleObject(m_hEvtThreadStart, INFINITE);
::ResetEvent(m_hEvtThreadStart);
if (nWait != WAIT_OBJECT_0)
return FALSE;
return TRUE;
}
2.Stop thread
void ThreadModel::StopThread()
{
if (m_hThread != NULL)
{
// try to Stop thread
::SetEvent(m_hEvtUserAbort);
// default wait 5 secs
if (::WaitForSingleObject(m_hEvtThreadOver, 5 * 1000) == WAIT_OBJECT_0)
{
// ok .
::ResetEvent(m_hEvtThreadOver);
}
else
{
// kill thread,but it is dangerous
::TerminateThread(m_hThread, 1);
m_hThread = NULL;
}
}
else
::ResetEvent(m_hEvtThreadOver);
}
3.Wait thread over
BOOL ThreadModel::WaitThread(DWORD nTimeOut /*= INFINITE*/)
{
if (NULL == m_hThread)
return FALSE;
BOOL result = (WaitForSingleObject(m_hEvtThreadOver, nTimeOut) == WAIT_OBJECT_0)?true:false;
if (!result)
{
::TerminateThread(m_hThread, 1);
m_hThread = NULL;
}
return result;
}
How to use it?
The ThreadModel Class provides two ways to use it.
1.the UI-thread create the worker thread, the worker thread is running until the UI-thread execute "StopThread" method to end the worker thread. The derived class ThreadSample1 show the way.
2.the UI-thread create the worker thread, and it will wait for the worker thread until it is over. The derived class ThreadSampl2 show how to implement it;
UINT ThreadSample::Run()
{
while(QueryExitEvent() == FALSE)
{
printf("%s\n","thread is running");
::Sleep(10);
}
return 0;
}
UINT ThreadSample2::Run()
{
for(int i = 0; i< 100; i++)
{
::Sleep(100);
printf("the thread2 is running\n");
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
//the sample1 of thread
ThreadSample ts;
ts.StartThread();
::Sleep(10000);
//the main thread stop the working thread
ts.StopThread();
printf("the thread is over");
//the sample2 of thread
ThreadSample2 ts2;
ts2.StartThread();
//the main thread is waiting until the working is over
BOOL bRet = ts2.WaitThread();
{
printf("the thread2 is over");
}
return 0;
}