Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

CThread - a Worker Thread wrapper class

0.00/5 (No votes)
3 Dec 1999 2  
A class that allows the simple implementation of worker threads

Contents

Preface

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 a CThread object. The first parameter is a void pointer and the second is LPARAM value. Void pointer may point to an arbitrary useful object (an owner of this thread e.g.) or to be a HWND Window handle with which the CThread 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 the CThread context. Keep in mind that CThread threads are maintained by the specific CThread architecture. Creating threads in the terms of CThread class means various internal allocations, settings and synchronization-registering (in the Thread-Handler-Oriented Synchronization model) that are correctly removed only by using the specific CThread operations (leaving the thread controlling function, CThread class destructor, Stop() and Kill() methods). Termination of a thread by e.g. ::TerminateThread() Windows function, bypasses the unregistration model provided by the CThread 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 the CThread 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 of GetThreadExitCode() 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 the GetHandle() 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, all CThread -specific internal allocations and registering are to be closed at the end of the CThread session. CThread class itself accomplishes this stuff automatically when the corresponding Windows thread naturally finishes (leaves the thread controlling function mapped to the CThread's ThreadHandler() method). Otherwise CThread 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 the CThread thread explicitly:
    1. 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.
    2. 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.
    3. CThread object going out of scope invokes a destructor that kills the Windows thread by calling the Kill() method (see the previous point). Ugly not recommended way.

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

Overviews
Modules

Help file built: 08/30/99

About Autoduck


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


Modules


Overviews


Structures and Enums


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

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
[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 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
[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 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
[in] Desired command to be handled immediately.

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
[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

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
[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. 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
[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

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
[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

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
[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 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
[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::~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 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 in CThread 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 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
[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 the CThread-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  Activity Status Predefined Values {
   THREAD_CREATED,
   THREAD_STOPPED,
   THREAD_RUNNING,
   THREAD_PAUSED,
   THREAD_CONTINUING,
   THREAD_PENDING,
   THREAD_USER_ACTIVITY,
};

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  General Predefined Values {
   DW_OK,
   DW_ERROR,
   DW_UNDEFINED,
   DW_TIMEOUT_ELAPSED,
   DW_INFINITE,
};

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  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
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).

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here