📄 developer.htm
字号:
<p class=MsoNormal style='text-align:justify'><i
style='mso-bidi-font-style:normal'><span style='font-size:11.0pt;mso-bidi-font-size:
10.0pt'>Notificable Threads</span></i><span style='font-size:11.0pt;mso-bidi-font-size:
10.0pt'> react to the owner-thread incoming commands and allow the owner to
obtain the current thread activity status. Owner thread usually uses the <b
style='mso-bidi-font-weight:normal'>PostCommand() </b>method which fires an
appropriate command to the thread. Thread immediately reacts to the incoming
command (inside <b style='mso-bidi-font-weight:normal'>ThreadHandler()</b>
virtual method) and is responsible to handle this command. Simultaneously, the
thread should set the meaningful current activity status by using <b
style='mso-bidi-font-weight:normal'>SetActivityStatus()</b> method. Owner
thread uses <b style='mso-bidi-font-weight:normal'>GetActivityStatus()</b>
method to obtain the current status.<o:p></o:p></span></p>
<p class=MsoNormal style='text-align:justify'><span
style='font-size:11.0pt;mso-bidi-font-size:10.0pt'>To establish a <i
style='mso-bidi-font-style:normal'>Notificable</i> thread a developer has to
add the SUPPORT_THREAD_NOTIFICATION macro in his <b style='mso-bidi-font-weight:
normal'>CThread</b>-derived class constructor where the thread-task handler
(the virtual <b style='mso-bidi-font-weight:normal'>ThreadHandler()</b> 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 <i style='mso-bidi-font-style:normal'>Worker Thread
Class Generator </i>Wizard that is discussed in the chapter 2.<o:p></o:p></span></p>
<p class=MsoNormal style='text-align:justify'><span style='font-size:11.0pt;
mso-bidi-font-size:10.0pt'><![if !supportEmptyParas]><![endif]><o:p></o:p></span></p>
<p style='text-align:justify'><a name="Commands"><font size="4">Commands</font></a></p>
<p class=MsoNormal style='text-align:justify'><span style='font-size:11.0pt;
mso-bidi-font-size:10.0pt'><![if !supportEmptyParas]></span></p>
<p class=MsoNormal style='text-align:justify'><span
style='font-size:11.0pt;mso-bidi-font-size:10.0pt'>The user should always
communicate with <b style='mso-bidi-font-weight:normal'>CThread</b> notificable
threads via <i style='mso-bidi-font-style:normal'>commands</i>. <b
style='mso-bidi-font-weight:normal'>Start()</b>, <b style='mso-bidi-font-weight:
normal'>Pause()</b>, <b style='mso-bidi-font-weight:normal'>Continue()</b>, <b
style='mso-bidi-font-weight:normal'>Reset()</b>, <b style='mso-bidi-font-weight:
normal'>Stop()</b> or the general <b style='mso-bidi-font-weight:normal'>PostCommand()</b>
<b style='mso-bidi-font-weight:normal'>CThread</b> methods are intended for
such use. Although, this is not the only way how to communicate with <b
style='mso-bidi-font-weight:normal'>CThread</b> 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 <i style='mso-bidi-font-style:normal'>command</i>-communication.
The main benefit is a synchronized and logical access to the thread-task code.
Incoming commands fired from everywhere fill up an internal <b
style='mso-bidi-font-weight:normal'>CThread</b> command queue and are handled <i
style='mso-bidi-font-style:normal'>sequentially</i> in the same order they were
fired - first-in-first-out (<i style='mso-bidi-font-style:normal'>cyclic stack
mechanism</i>). For example, the calling sequence: <b style='mso-bidi-font-weight:
normal'>Start()</b>, <b style='mso-bidi-font-weight:normal'>Pause()</b>, <b
style='mso-bidi-font-weight:normal'>Continue()</b>, <b style='mso-bidi-font-weight:
normal'>Stop()</b> fired in one step will be handled exactly in the same order
in which they were called.<o:p></o:p></span></p>
<p class=MsoNormal style='text-align:justify'><b
style='mso-bidi-font-weight:normal'><span style='font-size:11.0pt;mso-bidi-font-size:
10.0pt'>CThread</span></b><span style='font-size:11.0pt;mso-bidi-font-size:
10.0pt'> class introduces four helper methods wrapping the <b style='mso-bidi-font-weight:
normal'>PostCommand()</b> method: <b style='mso-bidi-font-weight:normal'>Run()</b>,
<b style='mso-bidi-font-weight:normal'>Pause()</b>, <b style='mso-bidi-font-weight:
normal'>Continue()</b> and <b style='mso-bidi-font-weight:normal'>Reset()</b>.
All they do is just firing the corresponding command to a <b style='mso-bidi-font-weight:
normal'>CThread</b> 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 <b style='mso-bidi-font-weight:
normal'>ThreadHandler()</b> method when a developer decides to use these
helpers.<o:p></o:p></span></p>
<p class=MsoNormal style='text-align:justify'><span style='font-size:11.0pt;
mso-bidi-font-size:10.0pt'><![if !supportEmptyParas]><![endif]><o:p></o:p></span></p>
<p style='text-align:justify'><a name="Racing_Conditions"><font size="4"><b>Racing Conditions</b></font></a></p>
<p class=MsoNormal style='text-align:justify'><span style='font-size:11.0pt;
mso-bidi-font-size:10.0pt'><![if !supportEmptyParas]></span></p>
<p class=MsoNormal style='text-align:justify'><span
style='font-size:11.0pt;mso-bidi-font-size:10.0pt'>To avoid racing
discrepancies between threads, developers should follow several guidelines
while building an application using <b style='mso-bidi-font-weight:normal'>CThread</b>
threads. An owner thread is responsible for a <b style='mso-bidi-font-weight:
normal'>CThread</b> thread lifetime. From the child <b style='mso-bidi-font-weight:
normal'>CThread</b> thread point of view, thus, the owner thread exists during
the whole thread lifetime. The only responsibility for such thread is <i
style='mso-bidi-font-style:normal'>not</i> to destroy the owner thread explicitly.<o:p></o:p></span></p>
<p class=MsoNormal style='text-align:justify'><span
style='font-size:11.0pt;mso-bidi-font-size:10.0pt'>On the other hand, from the
owner-thread point of view, <b style='mso-bidi-font-weight:normal'>CThread</b>
thread may terminate unpredictably. <b style='mso-bidi-font-weight:normal'>CThread</b>
object, however, <i style='mso-bidi-font-style:normal'>guarantees</i> that each
<b style='mso-bidi-font-weight:normal'>CThread</b> method call will be
semantically properly executed regardless the attached Windows thread is alive
or not. In other words, none <b style='mso-bidi-font-weight:normal'>CThread</b>
method will hang after the thread will have been prematurely terminated.<o:p></o:p></span></p>
<p class=MsoNormal style='text-align:justify'><span
style='font-size:11.0pt;mso-bidi-font-size:10.0pt'>The owner thread (or any
thread) may utilize some <b style='mso-bidi-font-weight:normal'>CThread</b>
methods to find out the existence status of the thread (<b style='mso-bidi-font-weight:
normal'>IsAlive()</b>, <b style='mso-bidi-font-weight:normal'>GetExitCode()</b>,
<b style='mso-bidi-font-weight:normal'>GetActivityStatus()</b> etc.).
Furthermore, the owner thread may be notified by some user specific callback
that is initiated from within the <b style='mso-bidi-font-weight:normal'>CThread</b>
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 <i style='mso-bidi-font-style:
normal'>Trivial Threads</i>).<o:p></o:p></span></p>
<p class=MsoNormal style='text-align:justify'><span
style='font-size:11.0pt;mso-bidi-font-size:10.0pt'>For <b style='mso-bidi-font-weight:
normal'>CThread</b> 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.<o:p></o:p></span></p>
<p class=MsoNormal style='text-align:justify'><span style='font-size:11.0pt;
mso-bidi-font-size:10.0pt'><![if !supportEmptyParas]><![endif]><o:p></o:p></span></p>
<p style='text-align:justify'><a name="Synchronous_Versus_Asynchronous_Methods_Deadlocks"><font size="4"><b>Synchronous versus
Asynchronous Methods; Deadlocks</b></font></a></p>
<p class=MsoNormal style='text-align:justify'><span style='font-size:11.0pt;
mso-bidi-font-size:10.0pt'><![if !supportEmptyParas]></span></p>
<p class=MsoNormal style='text-align:justify'><span
style='font-size:11.0pt;mso-bidi-font-size:10.0pt'>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, <i style='mso-bidi-font-style:
normal'>PauseThread()</i> method called from the owner thread, <i
style='mso-bidi-font-style:normal'>PauseThread()</i> 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, <i style='mso-bidi-font-style:
normal'>SetEvent-WaitForSingleObject</i> programming model is used in this
schema.<o:p></o:p></span></p>
<p class=MsoNormal style='text-align:justify'><span
style='font-size:11.0pt;mso-bidi-font-size:10.0pt'>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 <i style='mso-bidi-font-style:normal'>PauseThread()</i> 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 <i style='mso-bidi-font-style:normal'>PauseThread()</i>
method hangs or fails the application may hang forever.<o:p></o:p></span></p>
<p class=MsoNormal style='text-align:justify'><span
style='font-size:11.0pt;mso-bidi-font-size:10.0pt'>Even worse situation occurs
when the thread tries to cooperate with the main GUI application using the <b
style='mso-bidi-font-weight:normal'>PostMessage()</b> and <b style='mso-bidi-font-weight:
normal'>SendMessage()</b> functions. If <i style='mso-bidi-font-style:normal'>PauseThread()</i>
is invoked in the application and the thread sends consequently some message
back to the application waiting for a response, this message <i
style='mso-bidi-font-style:normal'>cannot</i> be handled in the application.
The message is namely to be handled by the application thread but the
application thread is blocked by the <i style='mso-bidi-font-style:normal'>PauseThread()</i>
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.<o:p></o:p></span></p>
<p class=MsoNormal style='text-align:justify'><b
style='mso-bidi-font-weight:normal'><span style='font-size:11.0pt;mso-bidi-font-size:
10.0pt'>CThread</span></b><span style='font-size:11.0pt;mso-bidi-font-size:
10.0pt'> class uses synchronous methods as few as possible. There are just four
methods that works synchronously: <b style='mso-bidi-font-weight:normal'>Start()</b>
and <b style='mso-bidi-font-weight:normal'>Kill()</b> methods that are,
fortunately, not dangerous because of their principal independence from the
owner thread, and <b style='mso-bidi-font-weight:normal'>Stop()</b> and <b
style='mso-bidi-font-weight:normal'>WaitForActivityStatus()</b> methods for
which a special care has to be taken. For more information concerning these
methods refer to <i style='mso-bidi-font-style:normal'>CThread Reference Manual</i>
(CThread.hlp or CThread.htm).<o:p></o:p></span></p>
<p class=MsoNormal style='text-align:justify'><span
style='font-size:11.0pt;mso-bidi-font-size:10.0pt'>Instead of distinguishing
among many possible scenarios how to manage synchronous calls, <b
style='mso-bidi-font-weight:normal'>CThread</b> class provides only one general
method for such purposes: <b style='mso-bidi-font-weight:normal'>WaitForActivityStatus()</b>.
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 <i
style='mso-bidi-font-style:normal'>CThread Reference Manual</i>).<o:p></o:p></span></p>
<p class=MsoNormal style='text-align:justify'><span
style='font-size:11.0pt;mso-bidi-font-size:10.0pt'>Stopping <b
style='mso-bidi-font-weight:normal'>CThread</b> threads is discussed in details
in the next paragraph.<o:p></o:p></span></p>
<p class=MsoNormal style='text-align:justify'><span style='font-size:11.0pt;
mso-bidi-font-size:10.0pt'><![if !supportEmptyParas]><![endif]><o:p></o:p></span></p>
<p style='text-align:justify'><a name="CThread_and_GUI"><font size="4"><b>CThread and GUI</b></font></a></p>
<p class=MsoNormal style='text-align:justify'><span style='font-size:11.0pt;
mso-bidi-font-size:10.0pt'><![if !supportEmptyParas]></span></p>
<p class=MsoNormal style='text-align:justify'><b
style='mso-bidi-font-weight:normal'><span style='font-size:11.0pt;mso-bidi-font-size:
10.0pt'>CThread</span></b><span style='font-size:11.0pt;mso-bidi-font-size:
10.0pt'> object wraps a Windows worker thread. Nevertheless, the thread may be
used in GUI context as well. As a worker thread <b style='mso-bidi-font-weight:
normal'>CThread</b> 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 <b style='mso-bidi-font-weight:normal'>PostMessage()</b> and <b
style='mso-bidi-font-weight:normal'>SendMessage()</b> functions or methods
utilizing these functions implicitly. Using the <b style='mso-bidi-font-weight:
normal'>PostMessage()</b> function is generally considered as more safe.<o:p></o:p></span></p>
<p class=MsoNormal style='text-align:justify'><span
style='font-size:11.0pt;mso-bidi-font-size:10.0pt'>Sending messages from the <b
style='mso-bidi-font-weight:normal'>CThread</b> thread to the main application
message queue is preferred by using the Windows function <b style='mso-bidi-font-weight:
normal'>PostMessage(hWnd, nMsg, lParam, wParam)</b> 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 <b style='mso-bidi-font-weight:
normal'>CThread</b> context.<o:p></o:p></span></p>
<p class=MsoNormal style='text-align:justify'><span
style='font-size:11.0pt;mso-bidi-font-size:10.0pt'>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). <b style='mso-bidi-font-weight:
normal'>CThread</b> 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 <b style='mso-bidi-font-weight:normal'>CThread</b>
thread is accomplished by the <b style='mso-bidi-font-weight:normal'>CThread</b>'s
<b style='mso-bidi-font-weight:normal'>Stop()</b> method called from the main
application thread. <b style='mso-bidi-font-weight:normal'>Stop()</b> method is
primarily a synchronous method and should wait until the <b style='mso-bidi-font-weight:
normal'>CThread</b> thread actually finishes. If the <b style='mso-bidi-font-weight:
normal'>CThread</b> 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 <b style='mso-bidi-font-weight:normal'>DeleteAllItems()</b> use
implicit <b style='mso-bidi-font-weight:normal'>SendMessage()</b>
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 <b style='mso-bidi-font-weight:
normal'>Stop()</b> method in some message handler. This leads to a deadlock and
the application freezes.<o:p></o:p></span></p>
<p class=MsoNormal style='text-align:justify'><span
style='font-size:11.0pt;mso-bidi-font-size:10.0pt'>To get out of such
difficulties we have to use one 'tricky' method. Suppose we are using the <b
style='mso-bidi-font-weight:normal'>CThread</b> thread communication with the
application message queue (or, generally, with the application thread, e.g.
through <b style='mso-bidi-font-weight:normal'>SendMessage()</b>). First of
all, a developer has to define a special activity status, for example,
THREAD_PREPARED_TO_TERMINE in his <b style='mso-bidi-font-weight:normal'>CThread</b>-derived
class. This activity status describes the situation that the <b
style='mso-bidi-font-weight:normal'>CThread</b> 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 <b style='mso-bidi-font-weight:normal'>CThread</b>'s
<b style='mso-bidi-font-weight:normal'>ThreadHandler()</b> method is as
follows:<o:p></o:p></span></p>
<p class=MsoNormal style='margin-left:.25in;text-align:justify;text-indent:
3.3pt'><span style='font-size:11.0pt;mso-bidi-font-size:10.0pt'><span
style='mso-tab-count:1'>牋 </span>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -