https://www.codeproject.com/Articles/111/CThread-a-Worker-Thread-wrapper-class?msg=5361661#xx5361661xx
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 aCThread
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), theCThreadDerived3
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 byOpenProcessLocking()
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 hisCThread
-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 childCThread
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 thePostMessage()
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 theCThread
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. throughSendMessage()
). 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 theCThread
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</CODE> 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 theThreadHandler()
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</CODE> method UserSpecificCriticalCode(); Unlock(); // <CODE>CThread</CODE> 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 base CException
-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
Description
PROJECT : CThread
Class
SUBSYSTEM : CThread
Base Class
AUTHOR : Dominik Filipp, © 1999, Slovakia, Europe
DESCRIPTION:
Abstract Base CThread
Class implementation file.
CThread.h
Description
PROJECT : 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
SetActivityStatus
(int nActivityStatus)
- Set Thread Activity Status void Lock ()
- Lock Critical Code in Thread-Handler-Oriented Synchronization Mode void Unlock ()
- Unlock Critical Code in Thread-Handler-Oriented Synchronization Mode void WaitForNotification (int& nIncomingCommand, DWORD dwDefaultTimeout = CThread::DW_INFINITE)
- Wait for Incoming Commands BOOL HandleCommandImmediately (int nCommand)
- Handle Command Immediately Bypassing Other Pending Commands virtual DWORD ThreadHandler ()
- Main Thread Task Handler (Abstract Declaration) virtual void OnKill ()
- Make Specific Unallocations After The Thread Has Been Killed
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
throws CThreadException of type:
CThreadException::CANNOT_SIGNAL_NOTIFICATION_OBJECT
FiresCThread::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 handleCThread::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 byCThread
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 inCThread
-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
-
[in]
CThread
Owner object.
lParam
-
[in] General parameter passed to
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 theSECURITY_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
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
-
[out] Reference to the
CThread
Owner object being retrieved.
lParam
- [out] Reference to the LPARAM parameter 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 ThreadHandlermethod 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 PostCommandoriented 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 theCMD_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
- [in] Desired command to be handled immediately.
See Also
ThreadHandler
PostCommand
WaitForNotification
Back to CThread
CThread::IsAlive
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
- [in] Suggested WINDOWS thread exit code. (see 'TerminateThread()' WINDOWS function in Microsoft MSDN documentation). bCloseAnyway
-
[in] Closes the CThread-thread regardless the thread has been destroyed or not. By using this parameter the CThread-thread is correctly closed and unregistered even if the corresponding WINDOWS thread cannot be properly terminated. Users should call this method again (using 'bCloseAnyway = TRUE') if it's not possible to recover the termination failure - best way is to call it in the 'catch' clause for an exception thrown by this method. By enabling this parameter no any
CThreadException
exception is thrown.
See Also
OnKill
Stop
Back to CThread
CThread::Lock
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 ProcessUnlockmethods. 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
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 ofOnKill()
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 baseCThread::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 CloseProcessLockingmethod. 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
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 handleCThread::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 ThreadHandlermethod (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 theThreadHandler 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 theCThread
-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 whichThreadHandler 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
-
[in] Desired command fired from within the owner thread that is to be executed in
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. ProcessUnlockmethod 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
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 handleCThread::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
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 handleCThread::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
-
[in]
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
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
- [in] Pointer to the security attributes structure.
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
-
[in]
CThread
Owner object.
lParam
-
[in] General parameter passed to
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
-
[in] WINDOWS thread priority. 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
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
- [in] Desired WINDOWS thread stack size.
See Also
GetStackSize
Back to CThread
CThread::Start
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 SetAttributesor 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 appropriateCThreadException
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
- [out] WINDOWS thread exit code. dwTimeout
- [in] Timeout interval in tenths of second.
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
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 PostCommandmethod. 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 theCThread
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
-
[in] Desired
CThread
activity status that is to be reached.
dwTimeout
- [in] Timeout interval in tenths of second.
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 whichThreadHandler 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
- [out] Reference to the Command ID that was fired from within the owner thread. dwDefaultTimeout
- [in] Timeout interval in 'miliseconds'.
See Also
PostCommand
CThread
Predefined Commands
Back to CThread
CThread::~CThread
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 CException
CThreadException 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
SetThread
(CThread* pThread)
-
Set
CThread
Object Throwing an Exception
void
SetErrorMsg
(CString strErrorMsg)
- Set Error Message void SetErrorMsg (UINT nErrorMsgID)
- Set Error Message void SetType (int nType)
- Set Exception Type
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 inCThread
class are described in 'Parameters' section.
Parameters
-
pThread
-
[in]
CThread
object causing an exception.
strErrorMsg
- [in] String describing an exception origin. nExceptionType
- [in] Type of thrown exception. 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
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 predefinedCThreadException
types but the user may define own types in CThread
-Derived class. Predefined types used inCThread
class are described in 'Parameters' section.
Parameters
-
pThread
-
[in]
CThread
object causing an exception.
nErrorMsgID
- [in] Resource ID of the string describing an exception origin. nExceptionType
- [in] Type of thrown exception. 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
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
-
[in]
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
- [in] System error code returned by GetLastError() WINDOWS function.
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
- [in] Type of the Message Box to be displayed. nMessageID
- [in] Error message string resource ID.
Back to CThreadException
CThreadException::SetErrorMsg
void CThreadException::SetErrorMsg(CString strErrorMsg)
Sets an error message describing an exception origin.
Parameters
-
strErrorMsg
- [in] Error message string.
See Also
GetErrorMsg
Back to CThreadException
CThreadException::SetErrorMsg
void CThreadException::SetErrorMsg(UINT nErrorMsgID)
Sets an error message describing an exception origin.
Parameters
-
nErrorMsgID
- [in] Error message string resource ID.
See Also
GetErrorMsg
Back to CThreadException
CThreadException::SetThread
void CThreadException::SetThread(CThread* pThread)
Sets CThread
object that caused an exception.
Parameters
-
pThread
-
[in]
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 theCThread
-Derived class. Predefined types used in CThread
class are described in 'Parameters' section.
Parameters
-
nErrorMsgID
- [in] Exception type. 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
GetType
Back to CThreadException
CThread
Activity Status Predefined Values
enum <CODE>CThread </CODE>
Members
-
THREAD_CREATED
- Thread was successfully created (activity-status set by the Start() method). THREAD_STOPPED
- Thread is stopped. THREAD_RUNNING
- Thread is running. THREAD_PAUSED
- Thread is paused. THREAD_CONTINUING
- Thread is continuing. THREAD_PENDING
- Thread is pending. THREAD_USER_ACTIVITY
- Base offset for the user-defined activity status.
CThread
General Predefined Values
enum <CODE>CThread </CODE>
Members
-
DW_OK
- Exception origin not known. DW_ERROR
- WINDOWS Thread cannot be created. DW_UNDEFINED
- Thread is already started. DW_TIMEOUT_ELAPSED
- Thread termination failed. DW_INFINITE
- Infinite Timeout Interval.
CThread
Predefined Commands
enum <CODE>CThread </CODE>
Members
-
CMD_NONE
- No command received. CMD_TIMEOUT_ELAPSED
- Wait-timeout elapsed (not command). CMD_INITIALIZE
- Initialize thread task. CMD_RUN
- Run thread task. CMD_PAUSE
- Pause thread task. CMD_CONTINUE
- Continue thread task. CMD_RESET
- Reset thread task. CMD_STOP
- Stop thread task and leave controlling function. CMD_USER_COMMAND
- Base offset for the user-defined command.
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
- Exception origin not known. CANNOT_CREATE_THREAD
- WINDOWS Thread cannot be created. THREAD_ALREADY_STARTED
- Thread is already started. CANNOT_TERMINATE_THREAD
- Thread termination failed. CANNOT_CREATE_NOTIFICATION_OBJECT
- Internal notification error (not enough memory or access denied). CANNOT_SIGNAL_NOTIFICATION_OBJECT
- Internal notification error (not enough memory or access denied).