YOU CAN CODE!

 

With The Case Of UCanCode.net  Release The Power OF  Visual C++ !   HomeProducts | PurchaseSupport | Downloads  
Download Evaluation
Pricing & Purchase?
E-XD++Visual C++/ MFC Products
Overview
Features Tour 
Electronic Form Solution
Visualization & HMI Solution
Power system HMI Solution
CAD Drawing and Printing Solution

Bar code labeling Solution
Workflow Solution

Coal industry HMI Solution
Instrumentation Gauge Solution

Report Printing Solution
Graphical modeling Solution
GIS mapping solution

Visio graphics solution
Industrial control SCADA &HMI Solution
BPM business process Solution

Industrial monitoring Solution
Flowchart and diagramming Solution
Organization Diagram Solution

Graphic editor Source Code
UML drawing editor Source Code
Map Diagramming Solution

Architectural Graphic Drawing Solution
Request Evaluation
Purchase
ActiveX COM Products
Overview
Download
Purchase
Technical Support
  General Q & A
Discussion Board
Contact Us

Links

Get Ready to Unleash the Power of UCanCode .NET


UCanCode Software focuses on general application software development. We provide complete solution for developers. No matter you want to develop a simple database workflow application, or an large flow/diagram based system, our product will provide a complete solution for you. Our product had been used by hundreds of top companies around the world!

"100% source code provided! Free you from not daring to use components because of unable to master the key technology of components!"


VC++ Articles: Create Thread, CWinThread, AfxBeginThread

 
 Zoran M.Todorovic

Creating a thread is simple: You just call ::AfxBeginThread(...), supply a thread handler and voila, thread is started. No matter if you start a thread in a suspended or not suspended state, you know when the thread is started. However, thread destruction is a different story. 

In all but trivial applications, you have at least one thread which accesses data available also to other parts of the program or other threads. Acess to data should be synchronized using any of the Win32 available synchronization API. When destroying the thread, you should know when a thread stopped its execution so that you can destroy data structures (otherwise, you get an exception). 

Class TBaseThread is a simple class which encapsulates all code related to thread creation and its destruction. This is an abstract class - you have to derive a new class for each thread in your application. Reason for this is a thread handler - it is a virtual abstract function in a base class. 

Include file: 

class TBaseThread {
protected:
HANDLE EKillThread; // When set, thread will be killed
HANDLE EThreadIsDead; // Thread sets to indicate thread is finished
private:
CWinThread *Thread;
public:
static UINT __cdecl ThreadFunc(LPVOID);
public:
TBaseThread();
virtual ~TBaseThread();
virtual void Create(int mode = 0); // Start immediately
virtual void Destroy(void);
void DoExecute(void);
virtual void Execute(void) = 0; // Derived classes will supply implementation
virtual void Suspend(void);
virtual void Resume(void);
};
Source code file: 

TBaseThread::TBaseThread()
{
Thread = NULL;
}
TBaseThread::~TBaseThread()
{
DWORD exitCode;
if (Thread != NULL && ::GetExitCodeThread(Thread->m_hThread, &exitCode) && exitCode == STILL_ACTIVE)
Destroy();
}
// Mode argument specifies whether thread is created in a suspended state or not.
// = 0 to start thread immediatelly or = CREATE_SUSPENDED to create a thread in suspended state.
void TBaseThread::Create(int mode /* = 0 *
)
{
if (!Thread) {
// Auto reset, initially reset
EKillThread = ::CreateEvent(NULL,FALSE,FALSE,NULL);
EThreadIsDead = ::CreateEvent(NULL,FALSE,FALSE,NULL);
// Create the thread.
Thread = ::AfxBeginThread(ThreadFunc,this,THREAD_PRIORITY_NORMAL,0,mode);
}
}
void TBaseThread::Destroy(void)
{
if (Thread) {
// Tell thread to commit suicide
BOOL retcode = ::SetEvent(EKillThread);
if (!retcode)
TRACE0("SetEvent(EKillThread) in TBaseThread::Destroy() returned error\n");
// Wait for info that thread is killed
if (::WaitForSingleObject(EThreadIsDead,10000L) == WAIT_TIMEOUT) {
// Safe guard - if something is wrong then brutally kill thread
::TerminateThread(Thread->m_hThread,1);
}
// Wait a bit
::Sleep(10);
// Maybe not necessary, but just in case
Thread = NULL;
}
::CloseHandle(EKillThread);
::CloseHandle(EThreadIsDead);
}
// Thread handler
UINT TBaseThread::ThreadFunc(LPVOID arg)
{
TBaseThread *thread = (TBaseThread*)arg;
thread->DoExecute();
return 0;
}
void TBaseThread::DoExecute(void)
{
Execute(); // Abstract virtual function
::SetEvent(EThreadIsDead);
}
void TBaseThread::Suspend(void)
{
if (Thread)
Thread->SuspendThread();
}
void TBaseThread::Resume(void)
{
if (Thread)
Thread->ResumeThread();
}
How to use it: 
First, you have to derive a new class representing your thread (let's call it TMyThread). The only function that you must implement is Execute(). This is the actual thread handler which has one of the following 3 forms: 

Simple situation. Thread sleeps for 100ms, then it wakes up, processes whatever is needed and goes back to sleep. If it is woken up by local TBaseThread::EKillThread event, it exits. 

// Thread handler number 1.
void TMyThread::Execute(void)
{
DWORD retcode;
while (TRUE) {
// EKillThread is a protected data member of TBaseThread.
retcode = ::WaitForSingleObject(EKillThread,100L);
if (retcode == WAIT_OBJECT_0) {
break; // Thread owner signaled this thread to exit
} else if (retcode == WAIT_TIMEOUT) {
// Process data - thread specific code
}
}
}
More complex situation. Thread sleeps for 500ms. It can wake up for a number of reasons. 
o If it is a timeout, execute thread default action for timeout or do nothing 
o If it is a signalled ESave or ETrigger event (just an example), handle actions for these events. 
ESave or ETrigger event can be locally created (in derived virtual Create() member function) or specified via TMyThread constructor. 
// Thread handler number 2
void TMyThread::Execute(void)
{
HANDLE handles[3];
DWORD whichEvent;
handles[0] = EKillThread; // Protected data member of TBaseThread
handles[1] = ESave; // Application specific handle to event
handles[2] = ETrigger; // Application specific handle to event
while (TRUE) {
whichEvent = ::WaitForMultipleObjects(3,handles,FALSE,500L);
if (whichEvent == WAIT_TIMEOUT) {
// Timeout - add code
} else if (whichEvent == (WAIT_OBJECT_0 + 0)) {
// EKillThread signaled - thread owner requests thread termination
break; // Exit thread loop
} else if (whichEvent == (WAIT_OBJECT_0 + 1)) {
// Application specific ESave event is signalled - do whatever
} else if (whichEvent == (WAIT_OBJECT_0 + 2)) {
// Application specific ETrigger event is signalled - do whatever
}
}
}
In this case, thread executes its job and immediately exits. TBaseThread::Destroy() does not wait since EThreadIsDead is already in signalled state (done by TBaseThread::DoExecute() function).. 
// Thread handler number 3.
void TMyThread::Execute(void)
{
// do something and immediately exit
}
Declare an object of TMyThread class either in CWinApp derived class or your CDocument derived class. To start a thread, execute Create() member function specifying initial start mode (0 to start immediatelly or CREATE_SUSPENDED to create a thread in suspended state). To destroy a thread, execute Destroy() member function - this can take time to execute depending on your thread handle. 

 

Copyright ?1998-2022 UCanCode.Net Software , all rights reserved.
Other product and company names herein may be the trademarks of their respective owners.

Please direct your questions or comments to webmaster@ucancode.net