📄 chap12.html
字号:
<P>{</P>
<P> criticalSection.Lock();</P>
<P> for (int x=0; x<10; ++x)</P>
<P> dstArray[x] = array[x];</P>
<P> criticalSection.Unlock();</P>
<P>}</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">现在你有机会看到线程安全类是什么样式了,现在可以让这个类工作了。按照以下步骤修改前面的</FONT><FONT SIZE=3>Thread</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>程序来测试</FONT><FONT SIZE=3>CCountArray</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">1.	</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>使用</FONT><FONT SIZE=3>File/New</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>菜单命令添加一个新的</FONT><FONT SIZE=3>C++</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>头文件</FONT><FONT SIZE=3>CountArray.h</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,并将此头文件加入到</FONT><FONT SIZE=3>Thread</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>工程中,并在其中添加代码。</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">2.	</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>再次使用</FONT><FONT SIZE=3>File/New</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>菜单命令添加一个新的</FONT><FONT SIZE=3>C++</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>资源文件</FONT><FONT SIZE=3>CountArray.cpp</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,并在其中添加代码。</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">3.	</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>在</FONT><FONT SIZE=3>ThreadView.cpp</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>文件中,在</FONT><FONT SIZE=3>#include "afxmt.h"</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>下面加上:</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>#include "CountArray.h"</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">4.	</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>在</FONT><FONT SIZE=3>ThreadView.cpp</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>文件中,删除</FONT><FONT SIZE=3>CEvent threadStart</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>;和</FONT><FONT SIZE=3>CEvent threadEnd</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>语句,并加上下列语句:</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>CCountArray countArray;</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">5.	</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>从消息映射中删除下列语句:</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>ON_MESSAGE(WM_THREADENDED, OnThreadended)</P>
<P>ON_COMMAND(ID_STOPTHREAD, OnStopthread)</P>
<P>ON_WM_CREATE()</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">6.	</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>用下面两个函数更换</FONT><FONT SIZE=3>ThreadProc()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>函数。</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>UINT WriteThreadProc(LPVOID param)</P>
<P>{</P>
<P> for(int x=0; x<10; ++x)</P>
<P> {</P>
<P> countArray.SetArray(x);</P>
<P> ::Sleep(1000);</P>
<P> }</P>
<P> return 0;</P>
<P>}</P>
<P>UINT ReadThreadProc(LPVOID param)</P>
<P>{</P>
<P> int array1[10];</P>
<P> for (int x=0; x<20; ++x)</P>
<P> {</P>
<P> countArray.GetArray(array1);</P>
<P> char str[50];</P>
<P> str[0] = 0;</P>
<P> for (int i=0; i<10; ++i)</P>
<P> {</P>
<P> int len = strlen(str);</P>
<P> wsprintf(&str[len], "%d ", array1[i]);</P>
<P> }</P>
<P> ::MessageBox((HWND)param, str, "Read Thread", MB_OK);</P>
<P> }</P>
<P> return 0;</P>
<P>}</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">7.	</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>用下面的语句替换</FONT><FONT SIZE=3>OnStartthread()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>中的所有语句:</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>void CThreadView::OnStartthread() </P>
<P>{</P>
<P>	// TODO: Add your command handler code here</P>
<P>	HWND hWnd = GetSafeHwnd();</P>
<P> AfxBeginThread(WriteThreadProc, hWnd);</P>
<P> AfxBeginThread(ReadThreadProc, hWnd);</P>
<P>}</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">8.	</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>删除函数</FONT><FONT SIZE=3>OnStopthread()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>OnThreadended()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>OnCreate()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">9.	</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>在</FONT><FONT SIZE=3>ThreadView.h</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>删除下列语句:</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>const WM_THREADENDED = WM_USER + 100;</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">10.	</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>在</FONT><FONT SIZE=3>ThreadView.h</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>中删除下面的语句:</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>afx_msg void OnStopthread();</P>
<P>afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);</P>
<P>afx_msg LONG OnThreadended();</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">11.	</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>在资源编辑器中删除“线程”主菜单中的“停止线程”菜单选项。</P>
<P ALIGN="JUSTIFY">现在编译并运行</FONT><FONT SIZE=3>Thread</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>程序的新版本。当运行这个程序后,主窗口首先出现。选择“线程”主菜单中的“启动线程”菜单选项,首先弹出如图</FONT><FONT SIZE=3>12.4</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>所示的消息框显示当前受保护的数组的值。每次当你单击消息框的“确定”按钮,一个新的消息框又出现。这种消息框要出现</FONT><FONT SIZE=3>20</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>次。在消息框中列出的数组的值取决于单击消息框的“确定”按钮以销毁消息框所花的时间,因为第一个线程每一秒更新一次数组中的数据。</P>
<P ALIGN="CENTER"><IMG SRC="Image441.gif" tppabs="http://166.111.167.223/computer/cai/visual_c++_5.0_programming/Image441.gif" WIDTH=96 HEIGHT=62></P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P ALIGN="CENTER">图</FONT><FONT SIZE=1>12. 4 </FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1>读取数据对话框</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">如果没有线程同步,则在消息框中出现的数字将不会相同。</P>
<P ALIGN="JUSTIFY">如果仔细检查源代码,你会发现第一个线程</FONT><FONT SIZE=3>WriteThreadProc()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>在一个循环类十次调用</FONT><FONT SIZE=3>CCountArray</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>类的成员函数</FONT><FONT SIZE=3>SetArray()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。每一次</FONT><FONT SIZE=3>SetArray()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>函数将</FONT><FONT SIZE=3>criticalSection</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>给这个线程,修改受保护的数组的值,然后又释放对</FONT><FONT SIZE=3>criticalSection</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的所有权。注意函数</FONT><FONT SIZE=3>Sleep()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,它将这个线程挂起</FONT><FONT SIZE=3>1000</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>毫秒。</P>
<P ALIGN="JUSTIFY">第二个线程</FONT><FONT SIZE=3>ReadThreadProc()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>为了构造一个显示数组元素的字符串也在访问</FONT><FONT SIZE=3>criticalSection</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。但是如果</FONT><FONT SIZE=3>WriteThreadProc()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>正在用更新数组中元素的值,</FONT><FONT SIZE=3>ReadThreadProc()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>必须等待。反之也是对的,即</FONT><FONT SIZE=3>WriteThreadProc()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>不能够访问受保护的数据直到它重新从</FONT><FONT SIZE=3>ReadThreadProc()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>得到对</FONT><FONT SIZE=3>criticalSection</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的所有权。</P>
<P ALIGN="JUSTIFY">如果你希望测试一下</FONT><FONT SIZE=3>criticalSection</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>是否在起作用,把</FONT><FONT SIZE=3>SetArray()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>函数最后的</FONT><FONT SIZE=3>criticalSection.Unlock()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>删除。重新编译并运行该程序,这次没有消息框出现。因为</FONT><FONT SIZE=3>WriteThreadProc()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>完全占有了</FONT><FONT SIZE=3>criticalSection</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,这将导致系统一致将</FONT><FONT SIZE=3>ReadThreadProc()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>挂起,直到你退出这个程序。</P><DIR>
</FONT><FONT FACE="Arial" SIZE=3><P>(2)	</FONT><FONT FACE="黑体" LANG="ZH-CN" SIZE=3>使用</FONT><FONT FACE="Arial" SIZE=3>Mutex</FONT><FONT FACE="黑体" LANG="ZH-CN" SIZE=3>(互斥对象)</P></DIR>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">互斥对象有点象</FONT><FONT SIZE=3>critical section</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,但有些复杂,因为它不仅允许同一程序的线程之间,而且允许不同程序的线程之间共享资源。尽管在不同程序之间的线程同步超出了本章的范围,但是你可以通过替换</FONT><FONT SIZE=3>critical section</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>获得使用互斥对象的经验。</P>
<P ALIGN="JUSTIFY">下面是</FONT><FONT SIZE=3>CCountArray2</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>类的头文件。除了名称和互斥对象外,这个文件和原来的</FONT><FONT SIZE=3>CCountArray</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>完全相同。</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>#include "afxmt.h"</P>
<P>class CCountArray2</P>
<P>{</P>
<P>private:</P>
<P> int array[10];</P>
<P> CMutex mutex;</P>
<P>public:</P>
<P> CCountArray2() {};</P>
<P> ~CCountArray2() {};</P>
<P> void SetArray(int value);</P>
<P> void GetArray(int dstArray[10]);</P>
<P>};</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">下面是</FONT><FONT SIZE=3>CCountArray2</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的执行文件,正如你所看到的,尽管互斥对象和</FONT><FONT SIZE=3>critical section</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>提供相同的服务,但是二者使用起来还是有很多不同的。</P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -