CThread - a Worker Thread wrapper class






4.98/5 (38 votes)
Dec 4, 1999

304146

17431
A class that allows the simple implementation of worker threads
- Download self installing source package - 1.0 Mb
- Download full documentation - 92 Kb
- Download example project 1 - 35 Kb
- Download example project 2 - 165 Kb
Contents
Preface
CThread
Class Conception- Thread Task Paradigms
- Trivial Threads
- Notificable Threads
- Thread Synchronization
- Thread-Handler-Oriented Synchronization
- Single Thread Object Synchronization
- Process Synchronization
- Thread Notification
- Commands
- Racing Conditions
- Synchronous Versus Asynchronous Methods; Deadlocks
CThread
and GUI- Generating
CThread
-Derived Class Source Code - Implementing
CThread
Task Handler - Important Notes
- Additional Documentation
CThread
Specifics
Preface
CThread
class written in Microsoft Visual C++ is a wrapper class
that constitutes the base for the comfortable Windows worker thread handling in
the MFC environment. CThread
itself is an abstract class from which user
thread-specific classes have to be derived. CThread
class offers
the opportunities how to define, implement and handle thread objects. Most
functionality is done in this base class, a developer is just responsible to
implement a thread-specific task and handle incoming notifications fired from
the owner of the thread. CThread
class is fully compliant to the
Object-Oriented Paradigm.
CThread Class Conception
Thread-Task Paradigms
CThread
abstract class defines conception describing the main
requirements regarding the thread handling. There are two main paradigms
concerning thread task implementation:
Trivial Threads
Thread task is a simple sequence of commands that are to be done. After
starting the thread, the thread terminates after completing the whole task.
Owner thread (typically the main application thread) may communicate with a
CThread
thread by some intermediate object visible for both sides.
This communication, however, does not provide effective parent-child-thread
notifications. Maintaining all risky situations originating in such
communication requires an additional developer's effort. Using of this
conception is recommended for linear or straightforward heavyweight tasks, more
or less independent from the owner thread that do not require sophisticated or
intensive communication with the owner thread. CThread
thread
supporting this paradigm is called Trivial Thread.
Notificable Threads
In opposite to Trivial Threads, the thread task may be application-sensitive and listens to the owner thread commands. In this case the thread task is a loop in which thread waits for incoming notifications (commands). After receiving a command the thread executes this command. Incoming commands are handled sequentially in the thread task procedure. Simultaneously, the thread may set the current thread activity status to inform the owner thread.
Notificable Threads act as 'schedulers' or 'services'. That means, these threads execute their task on the owner thread demand and wait for another command. Usually the task executed in such thread should not be too long to allow an owner thread to make an effective controlling over the thread. This thread is called Notificable Thread.
CThread
class supports both paradigms but emphasizes developers
to use Notificable Threads.
Thread Synchronization
Thread-Handler-Oriented Synchronization
CThread
derived classes may utilize the special synchronization
feature that is implemented in the basic CThread
class. The
mentioned Thread-Handler-Oriented Synchronization is a powerful feature provided
by CThread
class. Developers do not have to deal too much with
synchronization among thread objects using the same thread-task handler (the
ThreadHandler()
method). They just use Lock()
or Unlock()
CThread
methods to lock the critical code that is to be executed exclusively in
the ThreadHandler()
method. Developers may, however, omit this synchronization
feature and define the CThread
derived class, which does not
support this kind of synchronization. It is up to the developer’s responsibility
to implement non-critical thread task or instantiate just one thread object in
such case.
Each CThread
derived class requiring its own
Thread-Handler-Oriented Synchronization must declare this feature explicitly
(this can be automatically established while working with Worker Thread Class
Generator Wizard).
This kind of synchronization is so-called Thread-Handler-Oriented. Suppose a
developer utilizes two CThread
derived classes
CThreadDerived1
and CThreadDerived2
and each class
implements its own ThreadHandler()
method. Let Thread11
and Thread12
are the instantiated objects of the class
CThreadDerived1
and Thread21 and Thread22 are the objects of the class
CThreadDerived2
. Thread11 is synchronized with Thread12 but not
with Thread21 or Thread22 and vice versa. All thread objects of the
CThreadDerived1
class are synchronized among each other (as well as all objects
of the CThreadDerived2
class) but the synchronization of CThreadDerived1
objects
is fully independent from the synchronization of CThreadDerived2
objects.
On the other hand, if the CThreadDerived3
class is derived from
the CThreadDerived2
but do not implement its own
ThreadHandler()
method (uses the handler implemented in the
CThreadDerived2
class), the CThreadDerived3
objects
are automatically synchronized with the CThreadDerived2
objects and
vice versa.
In a CThread
object-oriented hierarchy developers may design
several CThread
-derived classes for different purposes. Some of
them will implement the specific thread-task handlers the others will inherit
them. Thread-Handler-Oriented Synchronization allows developers to split
CThread
objects into the groups that contain CThread
-derived objects operating on the same thread-task handler. Thus, each
group defines its own thread-task handler and logically provides the
synchronization for all objects belonging to this group. On the other hand,
another group operates on a different thread-task handler, executing a
completely different task independent from another group, so the synchronization
has also to be independent from another group. Thread-Handler-Oriented
Synchronization establishes and maintains the independent synchronization for
each group automatically. All the developer has to do is to write the
SUPPORT_THREAD_SYNCHRONIZATION
(ClassName) macro in the constructor
in his CThread
-Derived ClassName class where the thread-task
handler (the virtual ThreadHandler()
method) is actually
implemented. Thread-Handler-Oriented Synchronization is supported for both
Trivial and Notificable CThread
Threads.
Single Thread Object Synchronization
CThread
class itself implements an internal synchronization.
This is the special synchronization feature that is not visible from within the
owner thread. Internal synchronization does not impact Lock()
or
Unlock()
mechanism mentioned in the above paragraph under any
circumstances. The benefit of the internal synchronization is a synchronized
access to critical CThread
methods while accessing the one instance
of CThread
object asynchronously.
This kind of synchronization is sometimes called Single Thread Object
Synchronization. If, for example, the childThread is an instance of
CThread
-Derived class, which is shared by two other (arbitrary)
threads parentThread1 and parentThread2, both these parent threads operate on
the childThread object asynchronously. The internal synchronization implemented
in CThread
class guarantees that all critical childThread methods
will be executed properly regardless the parent thread owning the current
childThread focus. The only care that must be taken is that none of the parent
threads deletes the childThread's CThread
object while another is
still operating on it.
Despite the given guaranty there is one situation where the concurrent operating on the same object may be confusing. It concerns mainly Notificable Threads and sending commands from the parent threads to the childThread. If both parent threads send several commands asynchronously to the childThread there is no any guaranty about which command will be actually handled in the childThread at a moment. The similar situation may occur also in Trivial Threads while setting up some important controlling object property (or variable) used in the childThread by both parent threads concurrently. For this reason, a concurrency-handling-of-one-object design has to be carefully prepared.
This kind of synchronization is established automatically while registering
CThread
class in an application process for both Trivial and
Notificable Threads.
Process Synchronization
CThread
-Derived class offers also a global locking mechanism,
which is exclusive for the whole process. The user may use ProcessLock()
or ProcessUnlock()
CThread
static methods (that
were previously opened by OpenProcessLocking()
method) wherever in
a code. These methods are static so there is no necessary to instantiate any
CThread
object. User may use this synchronization mechanism to
accomplish an exclusive access to the global-critical resources (opening the
file, common communication object, singleton etc.). Process Synchronization may
be used in an arbitrary part of the code not necessarily in CThread
tasks only.
The mentioned synchronization does not support an inter-process synchronization.
Thread Notification
Notificable Threads react to the owner-thread incoming commands and allow the
owner to obtain the current thread activity status. Owner thread usually uses
the PostCommand()
method which fires an appropriate command to the thread.
Thread immediately reacts to the incoming command (inside ThreadHandler()
virtual method) and is responsible to handle this command.
Simultaneously, the thread should set the meaningful current activity status by
using SetActivityStatus()
method. Owner thread uses
GetActivityStatus()
method to obtain the current status.
To establish a Notificable thread a developer has to add the
SUPPORT_THREAD_NOTIFICATION
macro in his
CThread
-Derived class constructor where the thread-task handler
(the virtual ThreadHandler()
method) is actually implemented. He
also has to implement the thread-task handler following the specific rules
discussed later. The whole stuff may be arranged automatically by using the
Worker Thread Class Generator Wizard that is discussed in the chapter 2.
Commands
The user should always communicate with CThread
notificable
threads via commands. Start(), Pause(), Continue(), Reset(), Stop()
or the general PostCommand() CThread
methods are intended
for such use. Although, this is not the only way how to communicate with
CThread
threads (we may, for example, use methods of a specific
object operating in the thread handler directly), it is highly recommended to
use the mentioned command-communication. The main benefit is a synchronized and
logical access to the thread-task code. Incoming commands fired from everywhere
fill up an internal CThread
command queue and are handled sequentially in the
same order they were fired - first-in-first-out (cyclic stack mechanism). For
example, the calling sequence: Start(), Pause(),
Continue(),
Stop()
fired in one step will be handled exactly in the same order in
which they were called.
CThread
class introduces four helper methods wrapping the
PostCommand()
method: Run(), Pause(), Continue() and
Reset()
. All they do is just firing the corresponding command to a
CThread
thread. These methods just remind the similar functionality
schema provided by schedulers or services. Developers may decide how to
interpret these methods or they may decide not to utilize them at all. What is
important is to handle an appropriate command in the ThreadHandler()
method when a developer decides to use these helpers.
Racing Conditions
To avoid racing discrepancies between threads, developers should follow
several guidelines while building an application using CThread
threads. An owner thread is responsible for a CThread
thread
lifetime. From the child CThread
thread point of view, thus, the
owner thread exists during the whole thread lifetime. The only responsibility
for such thread is not to destroy the owner thread explicitly.
On the other hand, from the owner-thread point of view, CThread
thread may terminate unpredictably. CThread
object, however,
guarantees that each CThread
method call will be semantically
properly executed regardless the attached Windows thread is alive or not. In
other words, none CThread
method will hang after the thread will
have been prematurely terminated.
The owner thread (or any thread) may utilize some CThread
methods to find out the existence status of the thread (IsAlive(),
GetExitCode(), GetActivityStatus()
etc.). Furthermore, the owner thread
may be notified by some user specific callback that is initiated from within the
CThread
thread to be invoked immediately when some important
situation occurs. Similarly, this thread may set up a useful variable (or an
object property) which is shared by the owner thread as well (in Trivial
Threads).
For CThread
threads cooperating among each other it is a
developer's responsibility how to maintain racing conditions. This usually
strongly depends on the concrete architecture of an application. In general,
avoiding racing problems requires a proper thread-communication design and an
additional developing effort. Developers may also consult some design-patterns
discussing this theme.
Synchronous versus Asynchronous Methods; Deadlocks
There is one big dilemma in a thread theory - "use or not to use" synchronous
methods for controlling of threads. An advantage of such schema is a guaranty
that each method sending a command to a child thread invoked from the owner
thread waits until the child thread actually completes the command. If, for
example, the thread is forced to be paused by some, for example,
PauseThread()
method called from the owner thread,
PauseThread()
will wait until the thread is actually paused. This
works fine for many worker threads that are more or less independent from their
owner threads. Usually, SetEvent-WaitForSingleObject programming model is used
in this schema.
Unfortunately, there are many cases when this schema is inapplicable. In GUI
applications requiring bi-directional communication between an application and a
thread this model is a priori inappropriate. Following the previous example, if
a GUI application calls the PauseThread()
method it may wait a long
time for the thread completion which leads to a message queue blocking. In this
situation the application hangs until the method is completed. Moreover, if for
any reason the PauseThread()
method hangs or fails the application
may hang forever.
Even worse situation occurs when the thread tries to cooperate with the main
GUI application using the PostMessage()
and SendMessage()
functions. If PauseThread()
is invoked in the application
and the thread sends consequently some message back to the application waiting
for a response, this message cannot be handled in the application. The message
is namely to be handled by the application thread but the application thread is
blocked by the PauseThread()
method. This is a serious situation
leading to an excellent deadlock. The only safe using of a synchronous
thread-controlling method in a GUI application is the case when the thread does
not require any task to be executed by the application thread while completing
the appropriate command.
CThread
class uses synchronous methods as few as possible. There
are just four methods that works synchronously: Start()
and
Kill()
methods that are, fortunately, not dangerous because of
their principal independence from the owner thread, and Stop() and
WaitForActivityStatus()
methods for which a special care has to be
taken. For more information concerning these methods refer to
CThread
Reference Manual (CThread.hlp or CThread.htm).
Instead of distinguishing among many possible scenarios how to manage
synchronous calls, CThread
class provides only one general method
for such purposes: WaitForActivityStatus()
. This method is called
from the owner thread and just waits until the thread sets up a desired thread
activity status. The method, however, requires a proper synchronous-call design
varying from case to case (see CThread
Reference Manual).
Stopping CThread
threads is discussed in details in the next
paragraph.
CThread
and GUI
CThread
object wraps a Windows worker thread. Nevertheless, the
thread may be used in GUI context as well. As a worker thread
CThread
object does not contain its own message queue and therefore
shares the same queue as the main application thread. Thread itself communicates
with this queue (or a Windows window procedure directly) usually via the
PostMessage()
and SendMessage()
functions or methods
utilizing these functions implicitly. Using thePostMessage()
function is generally considered as more safe.
Sending messages from the CThread
thread to the main application
message queue is preferred by using the Windows function PostMessage(hWnd,
nMsg, lParam, wParam)
requiring the original Windows HWND handle of the
main application window. Generally, there is no guaranty about lifetime of C++
objects originating in a different thread. These C++ objects have to be handled
carefully in the CThread
context.
Normally, there is not big problem while communicating with the message queue
belonging to the main application window (if no synchronous thread-controlling
methods are called from the main thread - see the previous paragraph).
CThread
thread posts messages to the main window in the same way as
other objects do in the main application. Posted message is added at the end of
the queue and sequentially handled. However, there is one important exception -
stopping the thread. Stopping the CThread
thread is accomplished by
the CThread's Stop()
method called from the main application
thread. Stop()
method is primarily a synchronous method and should
wait until the CThread
thread actually finishes. If the
CThread
thread is forced to stop from within the application but is
still communicating with the application thread or the message queue (and
eventually waiting for message completion - some methods like the List Control's
DeleteAllItems()
use implicit SendMessage()
notification), that thread may not be properly terminated. The thread waits for
the message completion that is to be done in the main application thread but the
application thread itself is blocked by the Stop()
method in some
message handler. This leads to a deadlock and the application freezes.
To get out of such difficulties we have to use one 'tricky' method. Suppose
we are using the CThread
thread communication with the application
message queue (or, generally, with the application thread, e.g. through
SendMessage()
). First of all, a developer has to define a special
activity status, for example, THREAD_PREPARED_TO_TERMINE
in his
CThread
-Derived class. This activity status describes the situation
that the CThread
thread having set up this activity status will not
utilize neither the application message queue nor the application thread any
more, thus, from this moment the thread will neither post nor send any Windows
message to the application. The fragment of code setting up this activity status
in the CThread's ThreadHandler()
method is as follows:
... case CThread::CMD_RUN: SetActivityStatus(CThread::THREAD_RUNNING); // communicate with the main application message // queue/application thread PostOrSendMessagesToTheApplication(); break; ... case CThread::CMD_STOP: // stop communication with the application CompleteCommunicationFinally(); // and set up the necessary status informing the application // that this thread will not utilize the message queue/thread any more SetActivityStatus(CThreadDerived::THREAD_PREPARED_TO_TERMINE); bContinue = FALSE; break; ....
The next step is to stop the CThread
thread from within the main
application (owner thread). The best way is to use the main frame's
OnClose()
method in main-frame applications (in dialog-based
applications the situation is described as well). The main idea is to suppress
closing the main frame window until the CThread
thread's activity
status is equal to THREAD_PREPARED_TO_TERMINE
. This is accomplished
by periodical firing the WM_CLOSE
message from within the
OnClose()
method to prevent an application-thread-blocking and
allowing the CThread
thread to complete its eventual message
handling. The whole mentioned stuff is accomplished in the following code in the
main application:
For main-frame-based applications (SDI, MDI):
CMainFrame::OnClose() { DWORD dwExitCode; // force the thread to stop but leave immediately // (the second parameter = 0) m_myThread.Stop(dwExitCode, 0); if (m_myThread.GetActivityStatus() != CThreadDerived::THREAD_PREPARED_TO_TERMINE) { // invoke this handler again (keeping the message // loop enabled for the final // CThread thread message handling as well as // preventing the application thread // from blocking) PostMessage(WM_CLOSE); } else { // here the <CODE>CThread thread doesn't use // the message queue/application thread // anymore, so we can stop the thread synchronously // to ensure that the thread // is actually terminated m_myThread.Stop(dwExitCode); // ... and close the main frame properly CFrameWnd::OnClose(); }; }
Analogically for dialog-based applications (we will use OnCancel() virtual method here - this method is not a message handler!):
CMyDialog::OnCancel() { DWORD dwExitCode; m_myThread.Stop(dwExitCode, 0); if (m_myThread.GetActivityStatus() != CThreadDerived::THREAD_MSG_SESSION_CLOSED) { // call this handler again // IDCANCEL is the dialog's 'Cancel' button resource ID PostMessage(WM_COMMAND, MAKEWPARAM((WORD)IDCANCEL, (WORD)IDCANCEL)); } else { m_myThread.Stop(dwExitCode); // ... and close the dialog properly CDialog::OnCancel(); }; }
In some specific cases more complex handling is needed. Developers may want
to use the special flag indicating the end of message handling initiated in the
CThread
thread. They may also want to stop the thread in some other
non-finalize method. But the basic idea not to block the application thread and
periodically call the stop-thread-handler by the PostMessage()
method sketched in the above code remains the same.
Generating
CThread
-Derived Class Source Code
CThread
-Derived classes can be generated automatically by using
the Worker Thread Class Generator Wizard enclosed in this delivery. A user may
choose the base CThread
derived class from which he wants to derive
his own Trivial or Notificable CThread
-Derived class and implements
the thread specific task by writing down the code in the ThreadHandler()
method skeleton. He may also establish some kind of synchronization or
share the synchronization already established in the selected base class. The
Worker Thread Class Generator workaround does not require any special
explanation and it's intuitive at first glance.
Implementing CThread
Task Handler
After generating the CThread
-Derived class source the developer
has to implement the thread handler at least in one such class (from the
class-object-hierarchy point of view). The thread handler is declared and
implemented in the *.h and *.cpp files as a virtual
method:CThreadDerived::ThreadHandler().
According to the article 1 the user may implement one of the two possible paradigms.
1. Trivial Thread: Simple sequence of commands. ThreadHandler()
in this case may look as follows:
DWORD CThreadDerived::ThreadHandler() { BOOL bEverythingOK; <command_1>; <command_2>; <command_3>; ... <command_n>; ... if (bEverythingOK) return CThread::DW_OK ; // return 0 if finished successfully else return CThread::DW_ERROR; // return –1 otherwise }
2. Notificable Thread: ThreadHandler()
implements the task which
is sensitive to the owner thread incoming commands. The owner thread may, in
turn, obtain the current thread activity status in an arbitrary phase of running
thread. Thread Handler() in such case should look somehow like this:
// CThread derived class supporting thread object synchronization
DWORD CThreadDerived::ThreadHandler()
{
BOOL bContinue = TRUE;
int nIncomingCommand;
do
{
WaitForNotification(nIncomingCommand, CThreadDerived::DEFAULT_TIMEOUT);
/////////////////////////////////////////////////////////////////////
// Main Incoming Command Handling:
/////////////////////////////////////////////////////////////////////
switch (nIncomingCommand)
{
case CThread::CMD_TIMEOUT_ELAPSED:
if (GetActivityStatus() != CThread::THREAD_PAUSED)
{
UserSpecificTimeoutElapsedHandler();
// fire CThread::CMD_RUN command immediately...
// ... from within this thread use always the
// following method when you
// want to fire an additional command.
// This method bypasses all incoming
// commands and forces the passed command
// to be handled immediately
HandleCommandImmediately(CMD_RUN);
}
break;
case CThread::CMD_INITIALIZE: // initialize Thread Task
// this command should be handled; it’s fired when the Thread starts
UserSpecificOnInitializeHandler();
// execute CThread::CMD_RUN command immediately
HandleCommandImmediately(CMD_RUN);
break;
case CThread::CMD_RUN: // handle 'OnRun' command
if (GetActivityStatus() != CThread::THREAD_PAUSED)
{
SetActivityStatus(CThread::THREAD_RUNNING);
UserSpecificOnRunHandler();
// the critical code which requires an exclusive handling
// for all threads operating on this handler
// (Thread-Handler-Oriented Synchronization)
Lock(); // <CODE>CThread method
UserSpecificCriticalCode();
Unlock(); // CThread
method
}
break;
case CThread::CMD_PAUSE: // handle 'OnPause' command
if (GetActivityStatus() != CThread::THREAD_PAUSED)
{
UserSpecificOnPauseHandler();
SetActivityStatus(CThread::THREAD_PAUSED);
}
break;
case CThread::CMD_CONTINUE: // handle 'OnContinue' command
if (GetActivityStatus() == CThread::THREAD_PAUSED)
{
SetActivityStatus(CThread::THREAD_CONTINUING);
UserSpecificOnContinueHandler();
// execute CThread::CMD_RUN command if necessary
HandleCommandImmediately(CMD_RUN);
}
break;
case CThreadDerived::CMD_USER_SPECIFIC:
// handle the user-specific command
UserSpecificOnUserCommandHandler();
break;
case CThread::CMD_STOP: // handle 'OnStop' command
UserSpecificOnStopHandler();
bContinue = FALSE; // ... and leave the thread function finally
break;
default: // handle unknown commands...
break;
};
} while (bContinue);
return (DWORD)CThread::DW_OK; //... if thread task completion OK
}
Establishing (and starting) thread objects of the CThreadDerived
class in the owner thread as well as handling these threads may look as
in the following example:
CMainProgram::HandleThreads(); { CThreadDerived thread1, thread2; // start threads try { thread1.Start(); thread2.Start(); ... thread1.Pause(); ... thread2.Continue(); // ... or send the user-specific command... // (must be recognizable in the ThreadHandler()) thread2.PostCommand(CThreadDerived::CMD_USER_SPECIFIC); ... // stop threads thread1.Stop(); // (synchronous) waits until the thread actually finishes thread2.Stop(); // (synchronous) waits until the thread actually finishes } catch (CThreadException* pe) { pe->ReportError(); pe->Delete(); }; }
Note 1:
The communication from the owner thread to the Notificable Thread should
always be established by sending the commands that are recognizable in the
ThreadHandler()
method.
Note 2:
Phrases using italic font in the mentioned source code list mean
CThreadDerived
specific methods or data members. All others are
Windows System functions or CThread
provided methods and data
members.
Important Notes
- A user may utilize
CThread
-constructor parameters while constructing aCThread
object. The first parameter is a void pointer and the second isLPARAM
value. Void pointer may point to an arbitrary useful object (an owner of this thread e.g.) or to be aHWND
Window handle with which theCThread
thread cooperates. During thread task operation the thread may notify the owner object if needed. For example, the running thread may set the task progress position in the progress bar implemented in the owner object. Thread must, of course, be familiar with the architecture of the owner object.
- While using
CThread
-threads users should not use those Windows thread-specific functions that are responsible for creation or termination of Windows threads in theCThread
context. Keep in mind thatCThread
threads are maintained by the specificCThread
architecture. Creating threads in the terms ofCThread
class means various internal allocations, settings and synchronization-registering (in the Thread-Handler-Oriented Synchronization model) that are correctly removed only by using the specificCThread
operations (leaving the thread controlling function,CThread
class destructor,Stop()
andKill()
methods). Termination of a thread by e.g.::TerminateThread()
Windows function, bypasses the unregistration model provided by theCThread
class which may result to several deadlocks or, even, to a crash. The following list contains Windows thread-specific functions that should not be used in theCThread
context:CreateThread()
CreateRemoteThread()
ExitThread()
TerminateThread()
ThreadProc()
CloseHandle()
(this especially may lead to a catastrophic failure)
Users may, of course, utilize the mentioned functions but under their own thread strategy omitting
CThread
features. - Users should also prefer the
CThread::GetExitCode()
method instead ofGetThreadExitCode()
Windows function. This method offers the valid thread-exit-code regardless the Windows thread is alive, destroyed or closed. The method works fine even if the handle belonging to the Windows thread is not more valid. - Although
CThread
class provides theGetHandle()
method returning a Windows handle of a running thread, this method must be used very carefully - if ever.CThread
architecture considers this value as an internal variable. The handle is automatically closed (and zeroed) after the thread leaves the thread controlling function. In general, the state of the handle is, therefore, unpredictable. Developers, therefore, have to take care about using the Windows thread handle regarding the thread lifetime in a specific application. - Opened
CThread
session must be properly "closed". That means, allCThread
-specific internal allocations and registering are to be closed at the end of theCThread
session.CThread
class itself accomplishes this stuff automatically when the corresponding Windows thread naturally finishes (leaves the thread controlling function mapped to the CThread'sThreadHandler()
method). OtherwiseCThread
object provides three possibilities how to stop the running thread and make the necessary clean up automatically. Users should always use only the following strategies while stopping theCThread
thread explicitly:
- CThread's
Stop()
method forces the thread to the regular stopping and the clean-up is accomplished automatically after leaving the ThreadHandler() method. The best way. - CThread's
Kill()
method destroys the running Windows thread and cleans up the whole contents on its own. Possible, but should be used in emergency cases only. CThread
object going out of scope invokes a destructor that kills the Windows thread by calling theKill()
method (see the previous point). Ugly not recommended way.
- CThread's
Additional Documentation
More detailed information concerning CThread
class can be found
in CThread
Reference Manual (CThread.hlp, CThread.htm and
CThread.doc files) in '/Doc' subdirectory of the main installation
directory.
Author: Dominik Filipp, © 1999, Bratislava, Slovakia, Europe
E-mail
address: Dominik.Filipp@work4.sk
CThread
Specifics
To display a list of topics by category, click any of the contents entries below. To display an alphabetical list of topics, choose the Index button.
C/C++ Elements
Classes and Class Members
Structures and Enums
Other
Help file built: 08/30/99
About Autoduck
The sources for this Help file were generated by Autoduck, the source code documentation tool that generates Print or Help files from tagged comments in C, C++, Assembly, and Basic source files.
For more information, contact Eric Artzt (erica@microsoft.com).
Classes and Class Members
- CThread Class
- CThreadException Class
Modules
Overviews
Structures and Enums
CThread
Activity Status Predefined ValuesCThread
General Predefined ValuesCThread
Predefined Commands- CThreadException Predefined Types
CThread
Class
The base MFC CObject-derived class that encapsulates WINDOWS Worker
Thread abilities. CThread
class offers many features that are
not implemented or supported by WINDOWS System. It allows to build up the
full-fledged OOP Class hierarchy, supports several levels of safe Thread
Synchronization as well as the Thread Notification. Detailed information how do CThreads work, how should be managed or handled can be found in the 'Developer.doc' documentation in '\\Doc' subdirectory of the main installation directory.
CThreadException Class
The baseCException
-derived class used in CThread
-Derived
classes.
License Conditions
This software is a freeware and may be freely used or distributed without restriction.CThread.cpp
DescriptionPROJECT : CThread
Class
SUBSYSTEM : CThread
Base Class
AUTHOR : Dominik Filipp, © 1999, Slovakia, Europe
DESCRIPTION:
Abstract Base CThread
Class implementation
file.
CThread.h
DescriptionPROJECT : CThread
Class
SUBSYSTEM : CThread
Base Class
AUTHOR : Dominik Filipp, © 1999, Slovakia, Europe
DESCRIPTION:
Abstract Base CThread
Class header
file.
CThread
class
CThread
class CThread: public CObject
CThread
Class Members
Class Members
Public Members:
- CThread(void* pOwnerObject = NULL, LPARAM lParam = 0L)
CThread
Constructor- virtual
~CThread()CThread
Destructor- SECURITY_ATTRIBUTES
GetAttributes() const- Get Thread Attributes
- DWORD
GetStackSize() const- Get Thread Stack Size
- HANDLE
GetHandle() const- Get Thread Handle
- DWORD
GetID() const- Get Thread ID
- DWORD
GetExitCode() const- Get Thread Exit Code
- int
GetActivityStatus() const- Get Thread Activity Status
- int
GetPriority() const- Get WINDOWS Thread Priority
- BOOL
IsAlive()- Check if Thread is Alive
- void
Start()- Start Thread
- void
Run()- Fire Run Command
- void
Pause()- Fire Pause Command
- void
Continue()- Fire Continue Command
- void
Reset()- Fire Reset Command
- BOOL
Stop(DWORD& dwExitCode, DWORD dwTimeout = CThread::DW_INFINITE)- Fire Stop Command
- void
Kill(DWORD dwExitCode = CThread::DW_OK, BOOL bCloseAnyway = FALSE)- Kill Thread
- void
PostCommand(int nCommand)- Post Command to Thread
- void
ResetCommands()- Cancel All Notification Commands
- void
SetOwnerParams(void* pOwnerObject, LPARAM lParam = 0L)- Set Owner Object Parameters
- void
GetOwnerParams(void*& pOwnerObject, LPARAM& lParam) const- Get Owner Object Parameters
- void
SetAttributes(LPSECURITY_ATTRIBUTES lpThreadAttributes = NULL)- Set Thread Attributes
- void
SetStackSize(DWORD dwStackSize = 0)- Set Thread Stack Size
- BOOL
SetPriority(int nPriority = THREAD_PRIORITY_NORMAL)- Set WINDOWS Thread Priority
- BOOL
WaitForActivityStatus(int nActivityStatus, DWORD dwTimeout = CThread::DW_INFINITE) const- Wait For the Desired
CThread
Activity Status- static void
OpenProcessLocking()- Open Process Synchronization
- static void
CloseProcessLocking()- Close Process Synchronization
- static void
ProcessLock()- Lock Critical Code in Process Synchronization Mode
- static void
ProcessUnlock()- Unlock Critical Code in Process Synchronization Mode
Class Members
Protected Members:
- void
CThread::CloseProcessLocking
static void CThread::CloseProcessLocking(void)Static method that closes the process synchronization that was previously
opened by OpenProcessLocking. The synchronization itself is
accomplished by calling ProcessLock and ProcessUnlock methods
between which is the critical code that is to be executed process-exclusively.
As a static method may be used wherever in the code without constructing
any CThread
object.
See Also
OpenProcessLocking
ProcessLock
ProcessUnlock
Back to CThread
CThread::Continue
void CThread::Continue(void)throws CThreadException of type:
CThreadException::CANNOT_SIGNAL_NOTIFICATION_OBJECT
Fires CThread::CMD_CONTINUE
Command and notifies CThread
object. Used in
the owner thread. This method is valid only if CThread
-Derived
class supports Thread Notification and CThread
thread has been
successfully started. Otherwise it has no any effect.
To use the method
properly the ThreadHandler method must be able to handle CThread::CMD_CONTINUE
Command as well as implement the specific task
corresponding to this command. This method returns immediately after the
command has been fired. The owner thread may, however, wait for completion of
the corresponding task by using the paradigm described in the
WaitForActivityStatus method.
This method is a helper method
simplifying the semantic control of Notificable CThread
threads acting in a
'scheduler' or 'service' - like manner. It's up to the developer's
responsibility how to interpret and implement (or refuse at all) this method.
For more information see 'Developer.doc' documentation.
See Also
PostCommand
WaitForActivityStatus CThread
Predefined Commands
Back to CThread
CThread::CThread
CThread::CThread(void* pOwnerObject = NULL, LPARAM
lParam = 0 )
CThread
constructor. User may pass a so-called 'Owner object' to
the CThread
class. The Owner object is an arbitrary object claimed
to be an owner of CThread
object. In such way the Owner object may
be notified by CThread
object while running the thread. Optional
LPARAM
parameter allows the user to pass an additional useful information. It's
up to the developer's responsibility how to interpret and implement the Owner
object parameters in CThread
-Derived class. CThread
class itself just stores the passed values. The mentioned parameters may
be also set up or read after CThread
object construction by calling
the SetOwnerParams and GetOwnerParams methods.
While
constructing CThread
object no any WINDOWS thread is being
started.
Parameters
- pOwnerObject
CThread
Owner object.
CThread
object. See Also
SetOwnerParams
GetOwnerParams
Back to CThread
CThread::GetActivityStatus
int CThread::GetActivityStatus(void)Gets the current CThread
activity status. This method is
normally called from within the owner thread to obtain the current activity of
the owned thread. CThread
class offers the predefined values as
seen in the 'Return Value' section.
Return Value
Current CThread
activity status.
- CThread::THREAD_CREATED
- Thread was successfully created (activity status set by the Start() method).
- CThread::THREAD_STOPPED
- Thread is stopped.
- CThread::THREAD_RUNNING
- Thread is running.
- CThread::THREAD_PAUSED
- Thread is paused.
- CThread::THREAD_CONTINUING
- Thread is continuing.
- CThread::THREAD_PENDING
- Thread is pending.
- CThread::THREAD_USER_ACTIVITY
- Base offset for user-defined activity statuses.
See Also
SetActivityStatus
Back to CThread
CThread::GetAttributes
SECURITY_ATTRIBUTES CThread::GetAttributes(void)Gets the WINDOWS thread security attributes (see WINDOWS Threads in Microsoft MSDN documentation).
Return Value
Fills up the SECURITY_ATTRIBUTES
structure with valid data. If the WINDOWS
thread is not created the SECURITY_ATTRIBUTES
structure is null-reset.
See Also
SetAttributes
Back to CThread
CThread::GetExitCode
DWORD CThread::GetExitCode(void)Gets CThread
thread exit code - a value that is returned by
ThreadHandler method - or, generally, it's a return value of the thread
controlling function. GetExitCode()
method returns the valid exit code
regardless the WINDOWS thread is alive or not.
Return Value
CThread
thread exit code.
Back to CThread
CThread::GetHandle
HANDLE CThread::GetHandle(void)Gets the WINDOWS thread handle (see WINDOWS Threads in Microsoft MSDN documentation).
Return Value
Handle of WINDOWS thread or NULL if the thread is not created.
Back to CThread
CThread::GetID
DWORD CThread::GetID(void)Gets the WINDOWS thread ID (see WINDOWS Threads in Microsoft MSDN documentation).
Return Value
WINDOWS thread ID or 0 if the thread is not created.
Back to CThread
CThread::GetOwnerParams
void CThread::GetOwnerParams(void*& pOwnerObject, LPARAM& lParam)Retrieves the CThread
Owner object parameters.
Parameters
- pOwnerObject
CThread
Owner object being retrieved.
See Also
SetOwnerParams
Back to CThread
CThread::GetPriority
int CThread::GetPriority(void)This method gets the WINDOWS thread priority. GetPriority()
just
encapsulates the WINDOWS GetThreadPriority()
function. For more information see
Win32 SDK Programmer's Reference.
Return Value
Current WINDOWS thread priority or THREAD_PRIORITY_ERROR_RETURN
if an error
occurs. Can be one of the following:
THREAD_PRIORITY_NORMAL
THREAD_PRIORITY_ABOVE_NORMAL
THREAD_PRIORITY_BELOW_NORMAL
THREAD_PRIORITY_HIGHEST
THREAD_PRIORITY_IDLE
THREAD_PRIORITY_LOWEST
THREAD_PRIORITY_TIME_CRITICAL
See Also
SetPriority
Back to CThread
CThread::GetStackSize
DWORD CThread::GetStackSize(void)Gets the WINDOWS thread stack size (see WINDOWS Threads).
Return Value
WINDOWS thread stack size.
See Also
SetStackSize
Back to CThread
CThread::HandleCommandImmediately
void CThread::HandleCommandImmediately(int nCommand)This helper method is used for immediate sending of CThread
commands fired from within the ThreadHandler method in the actual
Notificable CThread
thread.
In Notificable CThread
threads the ThreadHandler method contains the 'case' switch in
which incoming commands are handled. In some cases the resolved and executed
command has to immediately invoke (and handle) another internal command in this
'case' switch to properly complete its task. Users should not use the
PostCommand oriented methods in such case because the command queue may
not be empty. This queue may be namely filled up by another thread and, thus, an
additional internal completion command will be just posted at the end of the
queue. In consequence, the next handled command will be the first pending in the
queue and not that one intended to be handled immediately.
For this reason a
special command-handling mechanism is desired and is supported by this method.
Requested internal command to be handled immediately is stored in the standard
CThread
command queue as the first pending command bypassing all
already stored commands. Restoring of internal commands is accomplished by the
same method as other standard commands, by the WaitForNotification
method. The difference is that an internal command is handled always as the
first command.
As an example we may consider the starting of a
notificable CThread
thread. After starting the thread the
CMD_INITIALIZE
command is fired as the first command. This command is handled in
the corresponding 'case' branch in the ThreadHandler method, in which the
basic initialization is accomplished. As the next logical step after the
initialization is to get run the main thread task immediately. Thus, before
leaving the initialization 'case' branch the HandleCommandImmediately(CMD_RUN)
method is called. CMD_RUN
command fired in such manner bypasses all pending
commands and is returned (via the WaitForNotification method) back to the
'case' switch as the following command. All pending commands will be resolved
afterwards.
The term 'internal commands' means just another kind of
firing and handling of standard commands. Users use the same commands (more
precisely, command IDs) as in the PostCommand method.
This method
is valid only if CThread
-Derived class supports Thread Notification
and the CThread
thread has been successfully started. Otherwise it
has no any effect.
Important note:
This method should
be called only in the CThread
thread (in the ThreadHandler
method).
Return Value
TRUE if the command was inserted in the command queue.
Parameters
- nCommand
See Also
ThreadHandler
PostCommand
WaitForNotification
Back to CThread
CThread::IsAlive
BOOL CThread::IsAlive(void)Checks if the current CThread
thread is still alive.
Return Value
TRUE if the thread is alive otherwise FALSE.
Back to CThread
CThread::Kill
void CThread::Kill(DWORD dwExitCode = CThread::DW_OK, BOOL bCloseAnyway = FALSE )throws CThreadException of type:
CThreadException::CANNOT_TERMINATE_THREAD
This method kills the
WINDOWS thread connected to CThread
object. Used in the owner
thread. The method returns after the WINDOWS thread has been actually killed, or
some significant error occurs. CThread
threads should always
terminate either by leaving the thread-controlling function attached to the
WINDOWS thread or by calling Stop method in notificable threads. Killing threads is the last-chance stopping mechanism and should be used in
emergency cases only. While killing the thread by using this method the
OnKill virtual method is invoked to provide the last chance for making
necessary unallocations specific to the thread being killed.
For more
information see 'Terminating WINDOWS Threads' in Microsoft MSDN
documentation.
Parameters
- dwExitCode
CThreadException
exception is thrown. See Also
OnKill
Stop
Back to CThread
CThread::Lock
void CThread::Lock(void)Marks the beginning of the critical code to be 'Thread-Handler-Oriented'
synchronized. This special synchronization mechanism allows to lock the critical
code and make it exclusive for the first thread reaching this method.
Consequently all other CThread
objects that operate on the same
ThreadHandler are blocked until the thread unlocks the critical code.
Other threads operating on the different ThreadHandler are not blocked
and are synchronized in exactly same way in their own group. Thus, CThreads
objects can be splitted into the groups operating on the same
ThreadHandler method. Each group is synchronized independently to each
other.
All managing concerning this kind of synchronization is done
automatically, users do not care about any aspect of synchronization. All they
have to do is to use the Lock() and Unlock methods to bound the critical
code. Thread-Handler-Oriented synchronization is, however, not always
usable. If the user needs to lock the shared common object that cannot be
accessed simultaneously under any circumstances, he should use
ProcessLock and ProcessUnlock methods. These methods guarantee the
process-exclusive access to the critical code (but not an inter-process
exclusive access). Lock()
method must be followed by Unlock method in
a way to prevent eventual deadlocks.
This kind of synchronization can be
established by adding SUPPORT_THREAD_SYNCHRONIZATION(ClassName) macro to
the user CThread
-Derived class constructor in which
ThreadHandler method is implemented.
Important note:
Both Lock()
and Unlock()
methods may be called from within the
appropriate CThread
thread only (represented by the ThreadHandler()
method
body). The methods should not be published and cannot be delegated to other
threads - otherwise unpredictable deadlocks may arise.
See Also
Unlock
ProcessLock
ProcessUnlock
Back to CThread
CThread::OnKill
void CThread::OnKill(void)Virtual method that is invoked while the Kill method is being
executed. OnKill()
is called after the WINDOWS thread has been actually
destroyed. Users may unallocate all extra resources that were needed in the
CThread
-Derived instance object. Default version does nothing
users may, however, implement this method in their CThread
-Derived
class.
All extra resources should be referenced through
CThread
-Derived class member data, because in the moment of
OnKill()
execution all local variables in the ThreadHandler method are
not more valid - thread is already destroyed and its controlling function is
detached. OnKill()
virtual method doesn't have to call the base
CThread::OnKill()
method.
Note 1: Users should unallocate (detach,
close...) resources that rely only to the current instance of
CThread
-Derived object that is being killed. Keep in mind that in
some cases the same resources may be used by other running instances as well. In
this situation the user is responsible to clean up such shared resources.
Note 2: OnKill() method doesn't have to be invoked under any
circumstances. If the thread regularly finished before the Kill method
has been called the Kill method does nothing, thus, OnKill() method is
not invoked. OnKill() is normally used as a last chance emergency clean-up.
See Also
Kill
ThreadHandler
Back to CThread
CThread::OpenProcessLocking
static void CThread::OpenProcessLocking(void)Static method that opens the process synchronization. After the first call
the process synchronization is opened. Additional call of this method has no any
effect - the synchronization remains opened. The synchronization itself is
accomplished by calling ProcessLock and ProcessUnlock methods
between which is the critical code that is to be executed process-exclusively.
Opened process-synchronization should be finally closed by
CloseProcessLocking method. This locking mechanism does not support
an inter-process synchronization.
As a static method may be used
wherever in the code without constructing any CThread
object.
See Also
CloseProcessLocking
ProcessLock
ProcessUnlock
Back to CThread
CThread::Pause
void CThread::Pause(void)throws CThreadException of type:
CThreadException::CANNOT_SIGNAL_NOTIFICATION_OBJECT
Fires
CThread::CMD_PAUSE
Command and notifies CThread
object. Used in the
owner thread. This method is valid only if CThread
-Derived class
supports Thread Notification and CThread
thread has been
successfully started. Otherwise it has no any effect. To use the method
properly the ThreadHandler method must be able to handle
CThread::CMD_PAUSE
Command as well as implement the specific task corresponding
to this command.
This method returns immediately after the command has been
fired. The owner thread may, however, wait for completion of the corresponding
task by using the paradigm described in the WaitForActivityStatus method.
This method is a helper method simplifying the semantic control of
Notificable CThread
threads acting in a 'scheduler' or 'service' - like manner.
It's up to the developer's responsibility how to interpret and implement (or
refuse at all) this method.
For more information see 'Developer.doc'
documentation.
See Also
PostCommand
WaitForActivityStatus CThread
Predefined Commands
Back to CThread
CThread::PostCommand
void CThread::PostCommand(int nCommand)throws CThreadException of type:
CThreadException::CANNOT_SIGNAL_NOTIFICATION_OBJECT PostCommand()
method is the base method with which the owner thread may manage notificable
CThread
objects. By calling PostCommand() the owner thread fires
desired commands to the thread belonging to CThread
object. The
thread consequently receives a signal to leave WaitForNotification method
which is used in the ThreadHandler method (implemented in
CThread
-Derived class) and restores the command fired from the
owner thread. Obtained command is immediately executed in the thread body.
Developer is responsible to handle the fired command in the ThreadHandler
method. PostCommand() mechanism is the recommended way how to manage
CThread
objects. It's also the base concept for other
command-oriented methods like Start(), Pause(), Continue(), Reset() or Stop()
.
Each of these methods sets the appropriate command and sends a signal to the
thread which handles the command. Using this paradigm the thread notifications
coming from outside keep the synchronization features provided by CThread
class.
PostCommand()
method supports so-called 'stackable commands'
which allows the thread-owner process to pump all desired commands at one step.
All such commands will be resolved in the thread task body in exactly the same
order as they were pumped in the owner thread (cyclic stack mechanism). User may
define an arbitrary count of user-specific commands. For this purpose the CThread
class offers the start offset command ID: CThread::CMD_USER_COMMAND. All
command IDs below this value is reserved by CThread
class and
should not be used. In this case the user is responsible to handle the
user-specific command in the ThreadHandler method in the
CThread
-Derived class.
This method is valid only if
CThread
-Derived class supports Thread Notification. Thread
Notification may be established by adding SUPPORT_THREAD_NOTIFICATION
macro in
the CThread
-Derived class constructor in which ThreadHandler
method is actually implemented. Otherwise PostCommand()
method has no any
effect. This method is usable after the CThread
thread has been
successfully started. PostCommand()
returns immediately after the
command has been actually fired. The owner thread may, however, wait for
completion of the task corresponding to the fired command (implemented in the
ThreadHandler method) by using the paradigm described in the
WaitForActivityStatus method.
Detailed information how to use
this method as well as how to manage fired commands in the thread task body can
be found in the 'Developer.doc' documentation.
Parameters
- nCommand
CThread
task body - ThreadHandler. See Also
WaitForNotification
WaitForActivityStatus
HandleCommandImmediately CThread
Predefined Commands
Back to CThread
CThread::ProcessLock
static void CThread::ProcessLock(void)Static method that marks the beginning of the critical code that is to be
executed process-exclusively. ProcessUnlock method is the counterpart
of the ProcessLock()
method which bounds the end of the critical code. Both
methods should be used in a way to prevent eventual deadlocks. Before using the
method the process-synchronization must be opened by OpenProcessLocking
method. This locking mechanism does not support an inter-process
synchronization.
As a static method may be used wherever in the code
without constructing any CThread
object.
See Also
OpenProcessLocking
CloseProcessLocking
ProcessUnlock
Back to CThread
CThread::ProcessUnlock
static void CThread::ProcessUnlock(void)Static method that marks the end of the critical code that is to be executed
process-exclusively. ProcessLock method is the counterpart of
ProcessUnlock()
method which bounds the start of the critical code. Both methods
should be used in a way to prevent eventual deadlocks. Before using the method
the process-synchronization must be opened by OpenProcessLocking method.
This locking mechanism does not support an inter-process synchronization.
As a static method may be used wherever in the code without constructing
any CThread
object.
See Also
OpenProcessLocking
CloseProcessLocking
ProcessLock
Back to CThread
CThread::Reset
void CThread::Reset(void)throws CThreadException of type:
CThreadException::CANNOT_SIGNAL_NOTIFICATION_OBJECT
Fires
CThread::CMD_RESET
Command and notifies CThread
object. Used in the
owner thread. This method is valid only if CThread
-Derived class
supports Thread Notification and CThread
thread has been
successfully started. Otherwise it has no any effect. To use the method
properly the ThreadHandler method must be able to handle
CThread::CMD_RESET
Command as well as implement the specific task corresponding
to this command. This method returns immediately after the command has been
fired. The owner thread may, however, wait for completion of the corresponding
task by using the paradigm described in the WaitForActivityStatus method.
This method is a helper method simplifying the semantic control of
Notificable CThread
threads acting in a 'scheduler' or 'service' - like manner.
It's up to the developer's responsibility how to interpret and implement (or
refuse at all) this method.
For more information see 'Developer.doc'
documentation.
See Also
PostCommand
WaitForActivityStatus CThread
Predefined Commands
Back to CThread
CThread::ResetCommands
void CThread::ResetCommands(void)Cancels all thread-notification commands fired by the PostCommand
method and waiting in the queue to be processed. This method is useful when
the last important command is intended to be sent to the CThread
object. To ensure that no any other command is to be processed, the owner
thread may cancel all such commands pending in the CThread
command
queue.
See Also
PostCommand
WaitForNotification
Back to CThread
CThread::Run
void CThread::Run(void)throws CThreadException of type:
CThreadException::CANNOT_SIGNAL_NOTIFICATION_OBJECT
Fires
CThread::CMD_RUN
Command and notifies CThread
object. Used in the
owner thread. This method is valid only if CThread
-Derived class
supports Thread Notification and CThread
thread has been successfully started.
Otherwise it has no any effect. To use the method properly the
ThreadHandler method must be able to handle CThread::CMD_RUN
Command as
well as implement the specific task corresponding to this command.
This
method returns immediately after the command has been fired. The owner thread
may, however, wait for completion of the corresponding task by using the
paradigm described in the WaitForActivityStatus method.
This
method is a helper method simplifying the semantic control of Notificable
CThread
threads acting in a 'scheduler' or 'service' - like manner. It's up to
the developer's responsibility how to interpret and implement (or refuse at all)
this method.
For more information see 'Developer.doc' documentation.
See Also
PostCommand
WaitForActivityStatus CThread
Predefined Commands
Back to CThread
CThread::SetActivityStatus
void CThread::SetActivityStatus(int nActivityStatus)Sets CThread
activity status. CThread
activity
status describes the current CThread
activity. This method should be
meaningfully used in the ThreadHandler CThread
-Derived class
method. to inform the owner thread about the current CThread
object
activity. Owner thread may call GetActivityStatus method to restore the
current status. CThread
class offers the predefined values as
seen in the 'Parameters' section.
For more information how to use this
method see 'Developer.doc' documentation.
Parameters
- nActivityStatus
CThread
activity status.
See Also
GetActivityStatus
Back to CThread
CThread::SetAttributes
void CThread::SetAttributes(LPSECURITY_ATTRIBUTES lpThreadAttributes = NULL)Sets the WINDOWS thread security attributes (see WINDOWS Threads in Microsoft
MSDN documentation).
Thread attributes - if necessary - should be set before
CThread
thread is started.
Parameters
- lpThreadAttributes
SECURITY_ATTRIBUTES
structure may be created temporarily. Passing its
pointer to this method means copying the structure contents to the internal data
space of CThread
object. Therefore, thread attributes remain valid
regardless the SECURITY_ATTRIBUTES
structure (which 'lpThreadAttributes'
parameter points to) exists or not. See Also
GetAttributes
Back to CThread
CThread::SetOwnerParams
void CThread::SetOwnerParams(void* pOwnerObject, LPARAM lParam = 0)Sets CThread
Owner object parameters. User may pass a so-called
'Owner object' to the CThread
class. The Owner object is an
arbitrary object claimed to be an owner of CThread object. In such way the Owner
object may be notified by CThread
object while running the thread.
Optional LPARAM parameter allows the user to pass an additional useful
information. It's up to the developer's responsibility how to interpret and
implement the Owner object parameters in CThread
-Derived class.
CThread
class itself just stores the passed values. The mentioned
parameters can be read after the CThread
object construction by
calling the GetOwnerParams method.
Parameters
- pOwnerObject
CThread
Owner object.
CThread
object. See Also
GetOwnerParams
Back to CThread
CThread::SetPriority
DWORD CThread::SetPriority(int nPriority = THREAD_PRIORITY_NORMAL)This method sets the WINDOWS thread priority. The priority may be set after
the WINDOWS thread has been started. SetPriority()
just encapsulates the
WINDOWS SetThreadPriority()
function. For more information see Win32 SDK
Programmer's Reference.
Return Value
TRUE - the priority was properly set.
FALSE - the priority was not set or
the thread is not running.
Parameters
- nPriority
THREAD_PRIORITY_NORMAL
THREAD_PRIORITY_ABOVE_NORMAL
THREAD_PRIORITY_BELOW_NORMAL
THREAD_PRIORITY_HIGHEST
THREAD_PRIORITY_IDLE
THREAD_PRIORITY_LOWEST
THREAD_PRIORITY_TIME_CRITICAL
See Also
GetPriority
Back to CThread
CThread::SetStackSize
void CThread::SetStackSize(DWORD dwStackSize = 0)Sets the WINDOWS thread stack size (see WINDOWS Threads in Microsoft MSDN
documentation).
Thread stack size - if necessary - should be set before
CThread
thread is started.
Parameters
- dwStackSize
See Also
GetStackSize
Back to CThread
CThread::Start
void CThread::Start(void)throws CThreadException of types:
CThreadException::CANNOT_CREATE_THREAD,
CThreadException::THREAD_ALREADY_STARTED,
CThreadException::CANNOT_CREATE_NOTIFICATION_OBJECT,
CThreadException::CANNOT_SIGNAL_NOTIFICATION_OBJECT
This method
starts the WINDOWS thread connected to CThread
object. Used in the
owner thread. Once established the WINDOWS thread cannot be started again until
it terminates. Before starting a thread user may set up WINDOWS thread
attributes or thread stack size if necessary. This can be accomplished by
calling the SetAttributes or SetStackSize methods. In
notificable threads Start()
method fires CThread::CMD_INITIALIZE
Command
immediately after the WINDOWS thread was being established.
CThread::CMD_INITIALIZE
Command must be handled in the ThreadHandler
method.
This method is a synchronous method. It returns only if the
WINDOWS thread has been successfully started or some significant error occurs.
In this case the method returns immediately by throwing the appropriate
CThreadException
exception.
See Also
Stop
SetAttributes
SetStackSize
PostCommand
WaitForNotification
Back to CThread
CThread::Stop
BOOL CThread::Stop(DWORD& dwExitCode, DWORD dwTimeout = CThread::DW_INFINITE)throws CThreadException of type:
CThreadException::CANNOT_SIGNAL_NOTIFICATION_OBJECT
This method
stops the WINDOWS running thread connected to CThread
object. Used
in the owner thread. In notificable threads Stop() method fires
CThread::CMD_STOP Command immediately after the WINDOWS thread was asked to be
stopped. CThread::CMD_STOP Command must be handled in ThreadHandler
method to properly terminate the thread. If CThread
object does not
support Thread Notification, Stop() will wait until the WINDOWS thread actually
terminates. In both modes the method returns only in the case when the WINDOWS
thread actually terminates, the timeout interval elapses or some significant
error occurs. Otherwise it waits (synchronous stopping). When an immediate
return is required the user may set 'dwTimeout' variable to zero. In such case,
however, the user is responsible to find out if the thread actually runs or is
already stopped.
Return Value
Stop return status
- TRUE
- WINDOWS thread was properly stopped.
- FALSE
- WINDOWS thread was not stopped after the timeout interval elapsed.
Parameters
- dwExitCode
See Also
Start
PostCommand
WaitForNotification
Back to CThread
CThread::ThreadHandler
DWORD CThread::ThreadHandler(void)Main CThread-handler virtual abstract method declaration.
This method
is not implemented in the CThread
class and must be implemented at
least at one CThread
-Derived class in the CThread
class hierarchy. ThreadHandler()
method concentrates the whole task
that CThread
thread has to execute. The implementation itself
varies according to the type of CThread
thread operating on this
method (Trivial or Notificable Threads).
For Notificable CThread
threads the method contains a main loop with the
WaitForNotification method resolving incoming commands fired from the
owner thread.
Detailed information as well as the examples how to
implement, manage and use this method for both Trivial and Notificable
CThread
threads can be found in the 'Developer.doc'
documentation.
Return Value
Thread task completion exit code. Developers may define an arbitrary exit code here except the WINDOWS predefined constant = STILL_ACTIVE (0x00000103L), which indicates the thread-is-alive status.
See Also
PostCommand
WaitForNotification
HandleCommandImmediately
Back to CThread
CThread::Unlock
void CThread::Unlock(void)Marks the end of the critical code in Thread-Handler-Oriented synchronization
mode. This method must be preceded by Lock method.
Important note:
Both Lock()
and Unlock()
methods may
be called from within the appropriate CThread
thread only (represented by the
ThreadHandler()
method body). The methods should not be published and cannot be
delegated to other threads - otherwise unpredictable deadlocks may arise.
See Also
Lock
Back to CThread
CThread::WaitForActivityStatus
BOOL CThread::WaitForActivityStatus(int nActivityStatus, DWORD dwTimeout = CThread::DW_INFINITE)Waits until the desired CThread
activity status is reached. Used
in the owner thread. This is a "good-servant-but-bad-master" method. The
owner thread may fire an arbitrary command to the CThread
object by
the PostCommand method. That means, the PostCommand method fires a
command and returns immediately. However, in some cases the owner thread may
want to wait until the command is actually handled. For this reason the process
may use this method which waits until the desired activity status is set in the
ThreadHandler method. In this case the user is responsible to set the
desired activity status in the ThreadHandler by the
SetActivityStatus method. Using of this method requires an
implementation of the proper 'set-thread-activity-status' strategy. If, for
example, the desired activity status is not properly set or is immediately
rewritten by another value, the desired status is consequently never reached and
the WaitForActivityStatus()
method hangs. Sometimes the thread-synchronization
locking mechanism is necessary. WaitForActivityStatus()
method returns only
in the case when the desired activity status was actually reached or timeout
interval elapsed.
Note: The Start()
and Stop()
methods do not
have to be checked by this method. These methods are executed synchronously and
return when the CThread-thread actually starts or stops.
Important
note: If the CThread
thread utilizes the main
application message queue be aware of using this method. WaitForActivityStatus()
method blocks the application thread from which is called and may not allow the
CThread
thread to complete its task requiring the message queue
handling. This may lead to a deadlock. For more information see 'Developers.doc'
documentation.
Return Value
TRUE if the desired activity status is reached; FALSE if the timeout elapsed OR the thread has been prematurely terminated before the desired status was reached. Developers should always check this return value if there is no an explicit guaranty about the thread's lifetime.
Parameters
- nActivityStatus
CThread
activity status that is to be reached.
See Also
SetActivityStatus
PostCommand
ThreadHandler
Back to CThread
CThread::WaitForNotification
void CThread::WaitForNotification(int& nIncomingCommand, DWORD dwDefaultTimeout = CThread::DW_INFINITE)The main ThreadHandler notification method. This method must be
implemented inside the ThreadHandler method for Notificable CThread
threads (see 'Developer.doc' documentation). The method waits for
incoming notifications (commands) fired from the owner thread via
PostCommand method and returns immediately after the command was
received. Returned command has to be handled in ThreadHandler method.
User may, however, set the timeout interval which forces the method to
return after the timeout interval elapses.
This method is valid only if
CThread
-Derived class supports Thread Notification. Thread
Notification can be established by adding SUPPORT_THREAD_NOTIFICATION macro in
CThread
-Derived class constructor in which ThreadHandler
method is actually implemented. Otherwise it has no any effect and the method
returns immediately. This method is usable after the CThread
thread has been successfully started.
Detailed information how to
use this method as well as how to manage fired commands in the thread task
handler can be found in the 'Developer.doc' documentation.
Parameters
- nIncomingCommand
See Also
PostCommand CThread
Predefined
Commands
Back to CThread
CThread::~CThread
CThread::~CThread(void)
CThread
destructor. CThread
destructor kills the
running WINDOWS thread that was not previously stopped and closes the
CThread
notification mode.
Back to CThread
CThreadException class
CThreadException class CThreadException: public CExceptionCThreadException Class Members
Class Members
Public Members:
- CThreadException(CThread* pThread = NULL)
- CThreadException Constructor
- CThreadException(CThread* pThread, CString strErrorMsg, int nExceptionType = CThreadException::UNKNOWN_ERROR)
- CThreadException Constructor
- CThreadException(CThread* pThread, UINT nErrorMsgID, int nExceptionType = CThreadException::UNKNOWN_ERROR)
- CThreadException Constructor
- CThread*
GetThread() const- Get
CThread
Object- CString
GetErrorMsg() const- Get Error Message
- int
GetType() const- Get Type of Thrown Exception
- virtual int
ReportError(UINT nType = MB_OK, UINT nMessageID = 0)- Report Error
- static CString
GetLastSystemErrorMsg(DWORD dwSysErrorCode)- Get String Representation Corresponding to the System Error Code
Class Members
Protected Members:
- void
CThread
Object Throwing an Exception
CThreadException::CThreadException
CThreadException::CThreadException(CThread* pThread, CString strErrorMsg, int nExceptionType = CThreadException::UNKNOWN_ERROR)CThreadException constructor. General CThreadException class intended to be
used by CThread
-Derived classes. CThread
-Derived
methods should always throw CThreadException exceptions. To distinguish the
origin of thrown exceptions the user should use the type of CThreadException
exception. CThread
methods use predefined CThreadException types
but the user may define own types in CThread
-Derived class.
Predefined types used in CThread
class are described in
'Parameters' section.
Parameters
- pThread
CThread
object causing an exception.
See Also
SetThread
SetType
Back to CThreadException
CThreadException::CThreadException
CThreadException::CThreadException(CThread* pThread, UINT nErrorMsgID, int nExceptionType = CThreadException::UNKNOWN_ERROR)CThreadException
constructor. General CThreadException
class intended to be
used by CThread
-Derived classes. CThread
-Derived
methods should always throw CThreadException
exceptions. To distinguish the
origin of thrown exceptions the user should use the type of CThreadException
exception. CThread
methods use predefined CThreadException
types
but the user may define own types in CThread
-Derived class.
Predefined types used in CThread
class are described in
'Parameters' section.
Parameters
- pThread
CThread
object causing an exception.
See Also
SetThread
SetType
Back to CThreadException
CThreadException::CThreadException
CThreadException::CThreadException(CThread* pThread = NULL)CThreadException constructor. General CThreadException class intended to be
used by CThread
-Derived classes.
Parameters
- pThread
CThread
object causing an exception. See Also
SetThread
Back to CThreadException
CThreadException::GetErrorMsg
CString CThreadException::GetErrorMsg(void)Gets an error message describing an exception origin.
Return Value
Error message string describing an exception.
See Also
SetErrorMsg
Back to CThreadException
CThreadException::GetLastSystemErrorMsg
static CString CThreadException::GetLastSystemErrorMsg(DWORD dwSysErrorCode)Static method which returns the message text corresponding to the system error code. This error code should be returned by GetLastError() WINDOWS function immediately after the system error occurs.
Return Value
String representation of the system error code.
Parameters
- dwSysErrorCode
Back to CThreadException
CThreadException::GetThread
CThreadException::GetThread(void)Gets CThread
object that caused an exception.
Return Value
CThread
object that caused an exception.
See Also
SetThread
Back to CThreadException
CThreadException::GetType
int CThreadException::GetType(void)Gets the type of an exception. Types used in the CThread
class
are described in 'Return Value' section.
Return Value
Predefined types that may be thrown by CThread
methods are as
follows:
- CThreadException::UNKNOWN_ERROR
- Exception origin not known.
- CThreadException::CANNOT_CREATE_THREAD
- WINDOWS Thread cannot be created.
- CThreadException::THREAD_ALREADY_STARTED
- Thread is already started.
- CThreadException::CANNOT_TERMINATE_THREAD
- Thread termination failed.
- CThreadException::CANNOT_CREATE_NOTIFICATION_OBJECT
- Internal notification error.
- CThreadException::CANNOT_SIGNAL_NOTIFICATION_OBJECT
- Internal notification error.
See Also
SetType
Back to CThreadException
CThreadException::ReportError
int CThreadException::ReportError(UINT nType = MB_OK, UINT nMessageID = 0 )Displays an exception-error message in the standard Message Box.
Return Value
Message Box return value.
Parameters
- nType
Back to CThreadException
CThreadException::SetErrorMsg
void CThreadException::SetErrorMsg(CString strErrorMsg)Sets an error message describing an exception origin.
Parameters
- strErrorMsg
See Also
GetErrorMsg
Back to CThreadException
CThreadException::SetErrorMsg
void CThreadException::SetErrorMsg(UINT nErrorMsgID)Sets an error message describing an exception origin.
Parameters
- nErrorMsgID
See Also
GetErrorMsg
Back to CThreadException
CThreadException::SetThread
void CThreadException::SetThread(CThread* pThread)Sets CThread
object that caused an exception.
Parameters
- pThread
CThread
object that caused an exception. See Also
GetThread
Back to CThreadException
CThreadException::SetType
void CThreadException::SetType(UINT nErrorMsgID)Sets the type of an exception. CThread
-Derived methods should
always throw CThreadException
exceptions. To distinguish the origin of thrown
exceptions the user may define own types of CThreadException
exceptions in the
CThread
-Derived class. Predefined types used in CThread
class are described in 'Parameters' section.
Parameters
- nErrorMsgID
See Also
GetType
Back to CThreadException
CThread
Activity Status Predefined Values
enum <CODE>CThread Activity Status Predefined Values {
THREAD_CREATED,
THREAD_STOPPED,
THREAD_RUNNING,
THREAD_PAUSED,
THREAD_CONTINUING,
THREAD_PENDING,
THREAD_USER_ACTIVITY,
};
Members
- THREAD_CREATED
CThread
General Predefined Values
enum <CODE>CThread General Predefined Values {
DW_OK,
DW_ERROR,
DW_UNDEFINED,
DW_TIMEOUT_ELAPSED,
DW_INFINITE,
};
Members
- DW_OK
CThread
Predefined Commands
enum <CODE>CThread Predefined Commands {
CMD_NONE,
CMD_TIMEOUT_ELAPSED,
CMD_INITIALIZE,
CMD_RUN,
CMD_PAUSE,
CMD_CONTINUE,
CMD_RESET,
CMD_STOP,
CMD_USER_COMMAND,
};
Members
- CMD_NONE
CThreadException Predefined Types
enum CThreadException Predefined Types {
UNKNOWN_ERROR,
CANNOT_CREATE_THREAD,
THREAD_ALREADY_STARTED,
CANNOT_TERMINATE_THREAD,
CANNOT_CREATE_NOTIFICATION_OBJECT,
CANNOT_SIGNAL_NOTIFICATION_OBJECT,
};
Members
- UNKNOWN_ERROR