⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch27.htm

📁 VC使用大全。里面集合了VC使用的各种使用技巧。非常有用。
💻 HTM
📖 第 1 页 / 共 5 页
字号:

</ol>

<A HREF="BBfig09.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch27/BBfig09.gif"><b>Fig. 27.9</b></A>

<P><I>Add CountArray.h to the Thread project.</I></P>

<ol start=2>

<li><P> Again choose File, New, and create a new C++ source file called CountArray.cpp in this project. Enter the code from Listing 27.7.</P>

<li><P> Switch to ThreadView.cpp and then add the following line near the top of the file, after the line <font color="#008000">#include &quot;afxmt.h&quot;</font>, which you placed there previously:</P>

<pre><font color="#008000">#include &quot;CountArray.h&quot;</font></pre>

<li><P> Add the following line near the top of the file, after the <font color="#008000">CEvent threadEnd</font> line you placed there previously:</P>

<pre><font color="#008000">CCountArray countArray;</font></pre>

<li><P> Delete the <font color="#008000">CEvent threadStart</font> and <font color="#008000">CEvent threadEnd</font> lines from the file.</P>

<li><P> Delete the lines <font color="#008000">ON_MESSAGE(WM_THREADENDED</font>,<font color="#008000"> OnThreadended)</font>, <font color="#008000">ON_COMMAND(ID_STOPTHREAD</font>,<font color="#008000"> OnStopthread)</font>, and <font 
color="#008000">ON_WM_CREATE()</font> from the message map.</P>

<li><P> Replace the <font color="#008000">ThreadProc()</font> function with the thread functions shown in Listing 27.8.</P>

<P><I>Listing 27.8&#151;WriteThreadProc() and ReadThreadProc()</I></P>

<pre><font color="#008000">UINT WriteThreadProc(LPVOID param)</font></pre>

<pre><font color="#008000">{</font></pre>

<pre><font color="#008000">    for(int x=0; x&lt;10; ++x)</font></pre>

<pre><font color="#008000">    {</font></pre>

<pre><font color="#008000">        countArray.SetArray(x);</font></pre>

<pre><font color="#008000">        ::Sleep(1000);</font></pre>

<pre><font color="#008000">    }</font></pre>

<pre><font color="#008000">    return 0;</font></pre>

<pre><font color="#008000">}</font></pre>

<pre><font color="#008000">UINT ReadThreadProc(LPVOID param)</font></pre>

<pre><font color="#008000">{</font></pre>

<pre><font color="#008000">    int array[10];</font></pre>

<pre><font color="#008000">    for (int x=0; x&lt;20; ++x)</font></pre>

<pre><font color="#008000">    {</font></pre>

<pre><font color="#008000">        countArray.GetArray(array);</font></pre>

<pre><font color="#008000">        char str[50];</font></pre>

<pre><font color="#008000">        str[0] = 0;</font></pre>

<pre><font color="#008000">        for (int i=0; i&lt;10; ++i)</font></pre>

<pre><font color="#008000">        {</font></pre>

<pre><font color="#008000">            int len = strlen(str);</font></pre>

<pre><font color="#008000">            wsprintf(&amp;str[len], &quot;%d &quot;, array[i]);</font></pre>

<pre><font color="#008000">        }</font></pre>

<pre><font color="#008000">        ::MessageBox((HWND)param, str, &quot;Read Thread&quot;, MB_OK);</font></pre>

<pre><font color="#008000">    }</font></pre>

<pre><font color="#008000">    return 0;</font></pre>

<pre><font color="#008000">}</font></pre>

<li><P> Replace all of the code in the <font color="#008000">OnStartthread()</font> function with the following lines:</P>

<pre><font color="#008000">    HWND hWnd = GetSafeHwnd();</font></pre>

<pre><font color="#008000">    AfxBeginThread(WriteThreadProc, hWnd);</font></pre>

<pre><font color="#008000">    AfxBeginThread(ReadThreadProc, hWnd);</font></pre>

<li><P> Delete the <font color="#008000">OnStopthread()</font>, <font color="#008000">OnThreadended</font>, and <font color="#008000">OnCreate()</font> functions from the file.</P>

<li><P> Switch to the ThreadView.h file and delete the line <font color="#008000">const </font><font color="#008000">WM_THREADENDED = WM_USER + 100</font> from the listing.</P>

<li><P> Also in ThreadView.h, delete the lines <font color="#008000">afx_msg LONG </font><font color="#008000">OnThreadended(WPARAM wParam, LPARAM lParam)</font>, <font color="#008000">afx_msg void </font><font color="#008000">OnStopthread() </font>and 
<font color="#008000">afx_msg int OnCreate(LPCREATESTRUCT </font><font color="#008000">lpCreateStruct)</font> from the message map.</P>

<li><P> Using the resource editor, remove the Stop <U>T</U>hread command from the <U>T</U>hread menu.</P>

</ol>

<P>Now build and run the new version of the Thread application. When you do, the main window appears. Select the <U>T</U>hread, <U>S</U>tart Thread command to gets things hopping. The first thing you'll then see is a message box (Figure 27.10) displaying 
the current values in the guarded array. Each time you dismiss the message box, it reappears with the new contents of the array. The message box will reappear 20 times. The values you see listed in the message box depend upon how often you dismiss the 
message box. The first thread is writing new values into the array once a second, even as you're viewing the array's contents in the second thread.</P>

<A HREF="BBfig10.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch27/BBfig10.gif"><b>Fig. 27.10</b></A>

<P><I>This message box displays the current contents of the guarded array.</I></P>

<P>The important thing to notice is that at no time does the second thread interrupt when the first thread is changing the values in the array. You can tell that this is true because the array always contains ten identical values. If the first thread was 
interrupted as it modified the array, the ten values in the array would not be identical, as shown in Figure 27.11.</P>

<A HREF="BBfig11.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch27/BBfig11.gif"><b>Fig. 27.11</b></A>

<P><I>Without thread synchronization, you might see something like this in the </I><I>message box.</I></P>

<P>If you examine the source code carefully, you'll see that the first thread, named <font color="#008000">WriteThreadProc()</font>, is calling the array class's <font color="#008000">SetArray()</font> member function ten times within a <font 
color="#008000">for</font> loop. Each time through the loop, <font color="#008000">SetArray()</font> gives the thread the critical-section object, changes the array contents to the passed number, and then takes the critical-section object away again. Note 
the call to the <font color="#008000">Sleep()</font> function, which suspends the thread for the number of milliseconds given as the function's single argument.</P>

<P>The second thread, named <font color="#008000">ReadThreadProc()</font>, is also trying to access the same critical-section object in order to construct a display string of the values contained in the array. But if <font 
color="#008000">WriteThreadProc()</font> is currently trying to fill the array with new values, <font color="#008000">ReadThreadProc()</font> has to wait. The inverse is also true. That is, <font color="#008000">WriteThreadProc()</font> can't access the 
guarded data until it can regain ownership of the critical section from <font color="#008000">ReadThreadProc()</font>.</P>

<P>If you really want to prove that the critical-section object is working, remove the <font color="#008000">criticalSection.Unlock()</font> line from the end of the <font color="#008000">CCountArray</font> class's <font color="#008000">SetArray()</font> 
member function. Then compile and run the program. This time when you start the threads, no message box appears. Why? Because <font color="#008000">WriteThreadProc()</font> takes the critical-section object and never lets it go, which forces the system to 
suspend <font color="#008000">ReadThreadProc()</font> forever (or at least until you exit the program).</P>

<P><B>Using Mutexes</B></P>

<P>Mutexes are a lot like critical sections but are a little more complicated, because they enable safe sharing of resources not only between threads in the same application, but also between threads of different applications. Although synchronizing 
threads of different applications is beyond the scope of this chapter, you can get a little experience with mutexes by using them in place of critical sections.</P>

<P>Listing 27.9 is the <font color="#008000">CCountArray2</font> class's header file. Except for the new class name and the mutex object, this header file is identical to the original CountArray.h. Listing 27.10 is the modified class's implementation 
file. As you can see, the member functions look a lot different when they are using mutexes instead of critical sections, even though both objects provide essentially the same type of services.</P>

<P><I>Listing 27.9&#151;CCOUNTARRAY2.H&#151;The </I>CCountArray2<I> Class's Header File</I></P>

<pre><font color="#008000">#include &quot;afxmt.h&quot;</font></pre>

<pre><font color="#008000">class CCountArray2</font></pre>

<pre><font color="#008000">{</font></pre>

<pre><font color="#008000">private:</font></pre>

<pre><font color="#008000">    int array[10];</font></pre>

<pre><font color="#008000">    CMutex mutex;</font></pre>

<pre><font color="#008000">public:</font></pre>

<pre><font color="#008000">    CCountArray2() {};</font></pre>

<pre><font color="#008000">    ~CCountArray2() {};</font></pre>

<pre><font color="#008000">    void SetArray(int value);</font></pre>

<pre><font color="#008000">    void GetArray(int dstArray[10]);</font></pre>

<pre><font color="#008000">};</font></pre>

<P><I>Listing 27.10&#151;COUNTARRAY2.CPP&#151;The </I>CCountArray2<I> Class's Implementation File</I></P>

<pre><font color="#008000">#include &quot;stdafx.h&quot;</font></pre>

<pre><font color="#008000">#include &quot;CountArray2.h&quot;</font></pre>

<pre><font color="#008000">void CCountArray2::SetArray(int value)</font></pre>

<pre><font color="#008000">{</font></pre>

<pre><font color="#008000">    CSingleLock singleLock(&amp;mutex);</font></pre>

<pre><font color="#008000">    singleLock.Lock();</font></pre>

<pre><font color="#008000">    for (int x=0; x&lt;10; ++x)</font></pre>

<pre><font color="#008000">        array[x] = value;</font></pre>

<pre><font color="#008000">}</font></pre>

<pre><font color="#008000">void CCountArray2::GetArray(int dstArray[10])</font></pre>

<pre><font color="#008000">{</font></pre>

<pre><font color="#008000">    CSingleLock singleLock(&amp;mutex);</font></pre>

<pre><font color="#008000">    singleLock.Lock();</font></pre>

<pre><font color="#008000">    for (int x=0; x&lt;10; ++x)</font></pre>

<pre><font color="#008000">        dstArray[x] = array[x];</font></pre>

<pre><font color="#008000">}</font></pre>

<P>In order to access a mutex object, you must create a <font color="#008000">CSingleLock</font> or <font color="#008000">CMultiLock</font> object, which performs the actual access control. The <font color="#008000">CCountArray2</font> class uses <font 
color="#008000">CSingleLock</font> objects, because this class is dealing with only a single mutex. When the code is about to manipulate guarded resources (in this case, the array), you create a <font color="#008000">CSingleLock</font> object, like 
this:</P>

<pre><font color="#008000">CSingleLock singleLock(&amp;mutex);</font></pre>

<P>The constructor's argument is a pointer to the thread-synchronization object that you want to control. Then, to gain access to the mutex, you call the <font color="#008000">CSingleLock</font> object's <font color="#008000">Lock()</font> member 
function:</P>

<pre><font color="#008000">singleLock.Lock();</font></pre>

<P>If the mutex is unowned, the calling thread becomes the owner. If another thread already owns the mutex, the system suspends the calling thread until the mutex is released, at which time the waiting thread is awakened and takes control of the 
mutex.</P>

<P>To release the mutex, you call the <font color="#008000">CSingleLock</font> object's <font color="#008000">Unlock()</font> member function. However, if you create your <font color="#008000">CSingleLock</font> object on the stack (rather than on the 
heap, using the <font color="#008000">new</font> operator) as shown in Listing 29.10, you don't have to call <font color="#008000">Unlock()</font> at all. When the function exits, the object goes out of scope, which causes its destructor to execute. The 
destructor automatically unlocks the object for you.</P>

<P>To try out the new <font color="#008000">CCountArray2</font> class in the Thread application, add new CountArray2.h and CountArray.cpp files to the Thread project and then delete the original CountArray.h and CountArray.cpp files. Finally, in 
ThreadView.cpp, change all references to <font color="#008000">CCountArray</font> to <font color="#008000">CCountArray2</font>. Because all the thread synchronization is handled in the <font color="#008000">CCountArray2</font> class, no further changes are 
necessary in order to use mutexes rather than critical sections. Convenient, eh?</P>

<P><B> Using Semaphores</B></P>

<P>Although semaphores are used like critical sections and mutexes in an MFC program, they serve a slightly different function. Rather than allowing only one thread to access a resource at a time, semaphores allow multiple threads to access a resource, 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -