📄 chap12.html
字号:
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">#include "stdafx.h"</P>
<P ALIGN="JUSTIFY">#include "CountArray2.h"</P>
<P ALIGN="JUSTIFY">void CCountArray2::SetArray(int value)</P>
<P ALIGN="JUSTIFY">{</P>
<P ALIGN="JUSTIFY"> CSingleLock singleLock(&mutex);</P>
<P ALIGN="JUSTIFY"> singleLock.Lock();</P>
<P ALIGN="JUSTIFY"> for (int x=0; x<10; ++x)</P>
<P ALIGN="JUSTIFY"> array[x] = value;</P>
<P ALIGN="JUSTIFY">}</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">void CCountArray2::GetArray(int dstArray[10])</P>
<P ALIGN="JUSTIFY">{</P>
<P ALIGN="JUSTIFY"> CSingleLock singleLock(&mutex);</P>
<P ALIGN="JUSTIFY"> singleLock.Lock();</P>
<P ALIGN="JUSTIFY"> for (int x=0; x<10; ++x)</P>
<P ALIGN="JUSTIFY"> dstArray[x] = array[x];</P>
<P ALIGN="JUSTIFY">}</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">为了访问一个互斥对象,你必须创建一个</FONT><FONT SIZE=3>CSingleLock</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>对象或一个</FONT><FONT SIZE=3>CMultiLock</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>对象,由它们来执行实际上的访问控制。</FONT><FONT SIZE=3>CCountArray2</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>类使用</FONT><FONT SIZE=3>CSingleLock</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>对象,因为这个类只处理单一的互斥对象。当代码准备操作受保护的资源,你应当创建一个</FONT><FONT SIZE=3>CSingleLock</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>对象,如下所示:</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>CSingleLock singleLock(&mutex);</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">这个构造函数的参数是一个指向你希望控制的线程同步对象的指针。接着为了获得对互斥对象的访问权限,你应当调用</FONT><FONT SIZE=3>CSingleLock</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的成员函数</FONT><FONT SIZE=3>Lock()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>:</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>singleLock.Lock();</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">如果互斥对象不被任何线程拥有,调用上述语句的线程将拥有该互斥对象。如果另外一个程序已经占有了互斥对象,系统将挂起调用上述语句的线程直到互斥对象被释放,此时被挂起的线程被唤醒并且占有互斥对象。</P>
<P ALIGN="JUSTIFY">为了释放这个互斥对象,你应该调用</FONT><FONT SIZE=3>CSingleLock</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>对象的成员函数</FONT><FONT SIZE=3>Unlock()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。然而,如果你是在栈中创建的</FONT><FONT SIZE=3>CSingleLock</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>对象,就不必调用</FONT><FONT SIZE=3>Unlock()</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>CCountArray2</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,向工程中添加新的</FONT><FONT SIZE=3>CountArray2.h</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>和</FONT><FONT SIZE=3>CountArray2.cpp</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>CountArray.cpp</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>CcountArray</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的代码全部换成</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><DIR>
</FONT><FONT FACE="Arial" SIZE=3><P>(3)	</FONT><FONT FACE="黑体" LANG="ZH-CN" SIZE=3>使用信号量(</FONT><FONT FACE="Arial" SIZE=3>Semaphore</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>MFC</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>0</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>时,不会再有其它线程被允许访问资源直到有释放了资源使计数器增加。</P>
<P ALIGN="JUSTIFY">在创建信号量时应当设置计数器的初始值和最大值,如下所示:</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>CSemaphore Semaphore(2, 2);</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">因为在本节中你将使用信号量创建线程安全类,因此需要声明一个</FONT><FONT SIZE=3>CSemaphore</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的指针作为成员变量,并且在类的构造函数中创建一个</FONT><FONT SIZE=3>CSemaphore</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>对象。</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>semaphore = new CSemaphore(2, 2);</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">一旦你创建了信号量对象,就开始计算资源访问。为了实现资源访问,首先应当创建一个</FONT><FONT SIZE=3>CSingleLock</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>对象</FONT><FONT SIZE=3>,</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>给它信号量的指针,如下:</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>CSingleLock singleLock(semaphore);</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">接着,为了减小信号量的计数器,应当调用</FONT><FONT SIZE=3>CSingleLock</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的成员函数</FONT><FONT SIZE=3>Lock()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>singleLock.Lock();</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">此时,信号量减小了内部的计数器。这个新的数目保持有效直到信号量被释放。通过调用</FONT><FONT SIZE=3>CSingleLock</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的成员函数</FONT><FONT SIZE=3>Unlock()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>singleLock.Unlock();</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">下面是一个新的类</FONT><FONT SIZE=3>CSomeResource</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。</FONT><FONT SIZE=3>CSomeResource</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>用来说明信号量的用法。这个类只有一个成员变量即指向</FONT><FONT SIZE=3>CSemaphore</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>对象的指针。</P>
<P ALIGN="JUSTIFY">下面是</FONT><FONT SIZE=3>CSomeResource</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>类的头文件</FONT><FONT SIZE=3>SOMERESOURCE.H</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>#include "afxmt.h"</P>
<P>class CSomeResource</P>
<P>{</P>
<P>private:</P>
<P> CSemaphore* semaphore;</P>
<P>public:</P>
<P> CSomeResource();</P>
<P> ~CSomeResource();</P>
<P> void UseResource();</P>
<P>};</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">下面是</FONT><FONT SIZE=3>CSomeResource</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>类的执行文件</FONT><FONT SIZE=3>SOMERESOURCE.CPP</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。从中可以看出,</FONT><FONT SIZE=3>CSemaphore</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>对象在构造函数中被创建,在析构函数中被删除。</FONT><FONT SIZE=3>UseResource()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>成员函数通过从信号量获得一个计数器来访问资源,然后当函数退出时释放信号量。</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>#include "stdafx.h"</P>
<P>#include "SomeResource.h"</P>
<P>CSomeResource::CSomeResource()</P>
<P>{</P>
<P> semaphore = new CSemaphore(2, 2);</P>
<P>}</P>
<P>CSomeResource::~CSomeResource()</P>
<P>{</P>
<P> delete semaphore;</P>
<P>}</P>
<P>void CSomeResource::UseResource()</P>
<P>{</P>
<P> CSingleLock singleLock(semaphore);</P>
<P> singleLock.Lock();</P>
<P> Sleep(5000);</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>CSomeResource</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>CCountArray</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>SomeResource.h</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>和</FONT><FONT SIZE=3>SomeResource.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>在新添加的两个文件中加入代码。</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">4.	</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>用</FONT><FONT SIZE=3>#include "SomeResource.h"</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>语句换掉</FONT><FONT SIZE=3>"CountArray2.h"</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">5.	</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>用</FONT><FONT SIZE=3>CSomeResource someResource;</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>替换</FONT><FONT SIZE=3>CCountArray2 countArray</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">6.	</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>。</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>UINT ThreadProc1(LPVOID param)</P>
<P>{</P>
<P> someResource.UseResource();</P>
<P> ::MessageBox((HWND)param,"Thread 1 had access.", </P>
<P>"Thread 1", MB_OK);</P>
<P> return 0;</P>
<P>}</P>
<P>UINT ThreadProc2(LPVOID param)</P>
<P>{</P>
<P> someResource.UseResource();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -