?? ch27.htm
字號:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
<!--
function popUp(pPage) {
var fullURL = document.location;
var textURL = fullURL.toString();
var URLlen = textURL.length;
var lenMinusPage = textURL.lastIndexOf("/");
lenMinusPage += 1;
var fullPath = textURL.substring(0,lenMinusPage);
popUpWin = window.open('','popWin','resizable=yes,scrollbars=no,width=525,height=394');
figDoc= popUpWin.document;
zhtm= '<HTML><HEAD><TITLE>' + pPage + '</TITLE>';
zhtm += '<link rel="stylesheet" href="/includes/stylesheets/ebooks.css"></head>';
zhtm += '<BODY bgcolor="#FFFFFF">';
zhtm += '<IMG SRC="' + fullPath + pPage + '">';
zhtm += '<P><B>' + pPage + '</B>';
zhtm += '</BODY></HTML>';
window.popUpWin.document.write(zhtm);
window.popUpWin.document.close();
// Johnny Jackson 4/28/98
}
//-->
</SCRIPT>
<link rel="stylesheet" href="/includes/stylesheets/ebooks.css">
<TITLE>Special Edition Using Visual C++ 6 -- Ch 27 -- Multitasking with Windows Threads</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF">
<CENTER>
<H1><IMG SRC="../button/que.gif" WIDTH="171" HEIGHT="66" ALIGN="BOTTOM" BORDER="0"><BR>
Special Edition Using Visual C++ 6</H1>
</CENTER>
<CENTER>
<P><A HREF="../ch26/ch26.htm"><IMG SRC="../button/previous.gif" WIDTH="128" HEIGHT="28"
ALIGN="BOTTOM" ALT="Previous chapter" BORDER="0"></A><A HREF="../ch28/ch28.htm"><IMG
SRC="../button/next.gif" WIDTH="128" HEIGHT="28" ALIGN="BOTTOM" ALT="Next chapter"
BORDER="0"></A><A HREF="../index.htm"><IMG SRC="../button/contents.gif" WIDTH="128"
HEIGHT="28" ALIGN="BOTTOM" ALT="Contents" BORDER="0"></A>
<HR>
</CENTER>
<CENTER>
<H1>- 27 -</H1>
</CENTER>
<CENTER>
<H1>Multitasking with Windows Threads</H1>
</CENTER>
<UL>
<LI><A HREF="#Heading1">Understanding Simple Threads</A>
<LI><A HREF="#Heading2">Understanding Thread Communication</A>
<UL>
<LI><A HREF="#Heading3">Communicating with Global Variables</A>
<LI><A HREF="#Heading4">Communicating with User-Defined Messages</A>
<LI><A HREF="#Heading5">Communicating with Event Objects</A>
</UL>
<LI><A HREF="#Heading6">Using Thread Synchronization</A>
<UL>
<LI><A HREF="#Heading7">Using Critical Sections</A>
<LI><A HREF="#Heading8">Using Mutexes</A>
<LI><A HREF="#Heading9">Using Semaphores</A>
</UL>
</UL>
<P>
<HR SIZE="4">
<CENTER>
<H1></H1>
</CENTER>
<P>When using Windows 95 (and other modern operating systems), you know that you
can run several programs simultaneously. This capability is called <I>multitasking.</I>
What you may not know is that many of today's operating systems also enable <I>threads,</I>
which are separate processes that are not complete applications. A thread is a lot
like a subprogram. An application can create several threads--several different flows
of execution--and run them concurrently. Threads give you the ability to have multitasking
inside multitasking. The user knows that he can run several applications at a time.
The programmer knows that each application can run several threads at a time. In
this chapter, you'll learn how to create and manage threads in your applications.</P>
<P>
<H2><A NAME="Heading1"></A>Understanding Simple Threads</H2>
<P>A thread is a path of execution through a program. In a multithreaded program,
each thread has its own stack and operates independently of other threads running
within the same program. MFC distinguishes between <I>UI threads</I>, which have
a message pump and typically perform user interface tasks, and <I>worker threads</I>,
which do not.</P>
<BLOCKQUOTE>
<P>
<HR>
<strong>NOTE:</strong> Any application always has at least one thread, which is the program's
primary or main thread. You can start and stop as many additional threads as you
need, but the main thread keeps running as long as the application is active. 
<HR>
</BLOCKQUOTE>
<P>A thread is the smallest unit of execution, much smaller than a <I>process</I>.
Generally each running application on your system is a process. If you start the
same application (for example, Notepad) twice, there will be two processes, one for
each instance. It is possible for several instances of an application to share a
single process: for example, if you choose File, New Window in Internet Explorer,
there are two applications on your taskbar, and they share a process. The unfortunate
consequence is that if one instance crashes, they all do.</P>
<P>To create a worker thread using MFC, all you have to do is write a function that
you want to run parallel with the rest of your application. Then call AfxBeginThread()
to start a thread that will execute your function. The thread remains active as long
as the thread's function is executing: When the thread function exits, the thread
is destroyed. A simple call to AfxBeginThread() looks like this:</P>
<P>
<PRE>AfxBeginThread(ProcName, param, priority);
</PRE>
<P>In the preceding line, ProcName is the name of the thread's function, param is
any 32-bit value you want to pass to the thread, and priority is the thread's priority,
which is represented by a number of predefined constants. Table 27.1 shows those
constants and their descriptions.</P>
<P>
<H4>Table 27.1  Thread Priority Constants</H4>
<P>
<TABLE BORDER="1">
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT"><B>Constant</B></TD>
<TD ALIGN="LEFT"><B>Description</B></TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">THREAD_PRIORITY_ABOVE_NORMAL</TD>
<TD ALIGN="LEFT">Sets a priority one point higher than normal.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">THREAD_PRIORITY_BELOW_NORMAL</TD>
<TD ALIGN="LEFT">Sets a priority one point lower than normal.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">THREAD_PRIORITY_HIGHEST</TD>
<TD ALIGN="LEFT">Sets a priority two points above normal.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">THREAD_PRIORITY_IDLE</TD>
<TD ALIGN="LEFT">Sets a base priority of 1. For a REALTIME_PRIORITY_CLASS process, this sets a priority
of 16.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">THREAD_PRIORITY_LOWEST</TD>
<TD ALIGN="LEFT">Sets a priority two points below normal.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">THREAD_PRIORITY_NORMAL</TD>
<TD ALIGN="LEFT">Sets normal priority.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">THREAD_PRIORITY_TIME_CRITICAL</TD>
<TD ALIGN="LEFT">Sets a base priority of 15. For a REALTIME_PRIORITY_CLASS process, this sets a priority
of 30.</TD>
</TR>
</TABLE>
<BLOCKQUOTE>
<P>
<HR>
<strong>NOTE:</strong> A thread's priority determines how often the thread takes control
of the system, relative to the other running threads. Generally, the higher the priority,
the more running time the thread gets, which is why the value of THREAD_PRIORITY_TIME_CRITICAL
is so high. 
<HR>
</BLOCKQUOTE>
<P>To see a simple thread in action, build the Thread application as detailed in
the following steps.</P>
<DL>
<DT></DT>
<DD><B>1. </B>Start a new AppWizard project workspace called <B>Thread</B>, as shown
in Figure 27.1.
<P>
</DL>
<P><A HREF="javascript:popUp('27uvc01.gif')"><B>FIG. 27.1</B></A><B> </B><I>Start
an AppWizard project workspace called </I><B>Thread</B><I>.</I></P>
<DL>
<DT><I></I></DT>
<DD><B>2. </B>Give the new project the following settings in the AppWizard dialog
boxes. The New Project Information dialog box will then look like Figure 27.2.
<P>
</DL>
<BLOCKQUOTE>
<P>Step 1: Single document</P>
<P>Step 2: Default settings</P>
<P>Step 3: Default settings</P>
<P>Step 4: Turn off all options</P>
<P>Step 5: Default settings</P>
<P>Step 6: Default settings</P>
</BLOCKQUOTE>
<P><A HREF="javascript:popUp('27uvc02.gif')"><B>FIG. 27.2</B></A><B> </B><I>These
are the AppWizard settings for the Thread project.</I></P>
<DL>
<DT><I></I></DT>
<DD><B>3. </B>Use the resource editor to add a Thread menu to the application's IDR_MAINFRAME
menu. Give the menu one command called <B>Start Thread</B> with a command ID of <B>ID_STARTTHREAD</B>,
and enter a sensible prompt and ToolTip, as shown in Figure 27.3.
<P>
</DL>
<P><A HREF="javascript:popUp('27uvc03.gif')"><B>FIG. 27.3</B></A><B> </B><I>Add a
Thread menu with a Start Thread command.</I></P>
<DL>
<DD><B>4. </B>Use ClassWizard to associate the ID_STARTTHREAD command with the OnStartthread()
message-response function, as shown in Figure 27.4. Make sure that you have <B>CThreadView</B>
selected in the Class Name box before you add the function.
<P>
</DL>
<P><A HREF="javascript:popUp('27uvc04.gif')"><B>FIG. 27.4</B></A><B> </B><I>Add the
OnStartthread() message-response function to the view class.</I></P>
<DL>
<DT><I></I></DT>
<DD><B>5. </B>Click the Edit Code button and then add the following lines to the
new OnStartthread() function, replacing the TODO: Add your command handler code here
comment:
<P>
</DL>
<PRE> HWND hWnd = GetSafeHwnd();
AfxBeginThread(ThreadProc, hWnd, THREAD_PRIORITY_NORMAL);
</PRE>
<P>This code will call a function called ThreadProc within a worker thread of its
own. Next, add ThreadProc, shown in Listing 27.1, to ThreadView.cpp, placing it right
before the OnStartthread() function. Note that ThreadProc() is a global function
and not a member function of the CThreadView class, even though it is in the view
class's implementation file.</P>
<P>
<H4>Listing 27.1  ThreadView.cpp--ThreadProc()</H4>
<PRE>UINT ThreadProc(LPVOID param)
{
::MessageBox((HWND)param, "Thread activated.", "Thread", MB_OK);
return 0;
</PRE>
<PRE>}
</PRE>
<P>This threaded function doesn't do much, just reports that it was started. The
SDK function MessageBox() is very much like AfxMessageBox(), but because this isn't
a member function of a class derived from CWnd, you can't use AfxMessageBox().</P>
<BLOCKQUOTE>
<P>
<HR>
<strong>TIP:</strong> The double colons in front of a function name indicate a call to a
global function, instead of an MFC class member function. For Windows programmers,
this usually means an API or SDK call. For example, inside an MFC window class, you
can call MessageBox("Hi, There!") to display <I>Hi, There!</I> to the user.
This form of MessageBox() is a member function of the MFC window classes. To call
the original Windows version, you write something like ::MessageBox(0, "Hi,
There!", "Message", MB_OK). Notice the colons in front of the function
name and the additional arguments.
<HR>
</BLOCKQUOTE>
<P>When you run the Thread program, the main window appears. Select the Thread, Start<B>
</B>Thread command, and the system starts the thread represented by the ThreadProc()
function and displays a message box, as shown in Figure 27.5.</P>
<P><A HREF="javascript:popUp('27uvc05.gif')"><B>FIG. 27.5</B></A><B> </B><I>The simple
secondary thread in the Thread program displays a message box and then ends.</I></P>
<P><I></I>
<H2><A NAME="Heading2"></A>Understanding Thread Communication</H2>
<P>Usually, a secondary thread performs some sort of task for the main program, which
implies that there needs to be a channel of communication between the program (which
is also a thread) and its secondary threads. There are several ways to accomplish
these communications tasks: with global variables, event objects, and messages. In
this section, you'll explore these thread-communication techniques.</P>
<P>
<H3><A NAME="Heading3"></A>Communicating with Global Variables</H3>
<P>Suppose you want your main program to be able to stop the thread. You need a way,
then, to tell the thread when to stop. One method is to set up a global variable
and then have the thread monitor the global variable for a value that signals the
thread to end. Because the threads share the same address space, they have the same
global variables. To see how this technique works, modify the Thread application
as follows:</P>
<DL>
<DT></DT>
<DD><B>1. </B>Use the resource editor to add a <B>Stop Thread</B> command to the
application's Thread menu. Give this new command the <B>ID_STOPTHREAD</B> ID, as
shown in Figure 27.6.
</DL>
<P><A HREF="javascript:popUp('27uvc06.gif')"><B>FIG. 27.6</B></A><B> </B><I>Add a
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -