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

📄 chap12_2.htm

📁 VC++教程电子图书
💻 HTM
📖 第 1 页 / 共 2 页
字号:
            </tr>
            <tr> 
              <td width="35%">
                <p align="JUSTIFY">WAIT_TIMEOUT
              </td>
              <td width="65%">
                <p align="JUSTIFY">超时返回。
              </td>
            </tr>
          </table>
          <p><b> </b></p>
          <p align="JUSTIFY"> <b></b><font color="#3973DE" face="Times New Roman">12.2.3 
            </font><font color="#3973DE">同步对象</font></p>
          <p align="JUSTIFY">  同步对象用来协调多线程的执行,它可以被多个线程共享。线程的等待函数用同步对象的句柄作为参数,同步对象应该是所有要使用的线程都能访问到的。同步对象的状态要么是有信号的,要么是无信号的。同步对象主要有三种:事件、mutex和信号灯。</p>
          <p align="JUSTIFY">  事件对象(Event)是最简单的同步对象,它包括有信号和无信号两种状态。在线程访问某一资源之前,也许需要等待某一事件的发生,这时用事件对象最合适。例如,只有在通信端口缓冲区收到数据后,监视线程才被激活。</p>
          <p align="JUSTIFY">  事件对象是用CreateEvent函数建立的。该函数可以指定事件对象的种类和事件的初始状态。如果是手工重置事件,那么它总是保持有信号状态,直到用ResetEvent函数重置成无信号的事件。如果是自动重置事件,那么它的状态在单个等待线程释放后会自动变为无信号的。用SetEvent可以把事件对象设置成有信号状态。在建立事件时,可以为对象起个名字,这样其它进程中的线程可以用OpenEvent函数打开指定名字的事件对象句柄。</p>
          <p align="JUSTIFY">  mutex对象的状态在它不被任何线程拥有时是有信号的,而当它被拥有时则是无信号的。mutex对象很适合用来协调多个线程对共享资源的互斥访问(mutually 
            exclusive)。</p>
          <p align="JUSTIFY">  线程用CreateMutex函数来建立mutex对象,在建立mutex时,可以为对象起个名字,这样其它进程中的线程可以用OpenMutex函数打开指定名字的mutex对象句柄。在完成对共享资源的访问后,线程可以调用ReleaseMutex来释放mutex,以便让别的线程能访问共享资源。如果线程终止而不释放mutex,则认为该mutex被废弃。</p>
          <p align="JUSTIFY">  信号灯对象维护一个从0开始的计数,在计数值大于0时对象是有信号的,而在计数值为0时则是无信号的。信号灯对象可用来限制对共享资源进行访问的线程数量。线程用CreateSemaphore函数来建立信号灯对象,在调用该函数时,可以指定对象的初始计数和最大计数。在建立信号灯时也可以为对象起个名字,别的进程中的线程可以用OpenSemaphore函数打开指定名字的信号灯句柄。</p>
          <p align="JUSTIFY">  一般把信号灯的初始计数设置成最大值。每次当信号灯有信号使等待函数返回时,信号灯计数就会减1,而调用ReleaseSemaphore可以增加信号灯的计数。计数值越小就表明访问共享资源的程序越多。</p>
          <p align="JUSTIFY">  除了上述三种同步对象外,表12.3中的对象也可用于同步。另外,有时可以用文件或通信设备作为同步对象使用。</p>
          <p align="JUSTIFY"><b> </b></p>
          <b> 
          <p align="CENTER">表12.3 可用于同步的对象</p>
          </b> 
          <table border="1" cellspacing="1" cellpadding="1" width="579">
            <tr> 
              <td width="22%"><b>
                <p align="JUSTIFY">对象
                </b></td>
              <td width="78%"><b>
                <p align="JUSTIFY">描述
                </b></td>
            </tr>
            <tr> 
              <td width="22%">
                <p align="JUSTIFY">变化通知
              </td>
              <td width="78%">
                <p align="JUSTIFY">由FindFirstChangeNotification函数建立,当在指定目录中发生指定类型的变化时对象变成有信号的。
              </td>
            </tr>
            <tr> 
              <td width="22%">
                <p align="JUSTIFY">控制台输入
              </td>
              <td width="78%">
                <p align="JUSTIFY">在控制台建立是被创建。它是用CONIN$调用CreateFile函数返回的句柄,或是GetStdHandle函数的返回句柄。如果控制台输入缓冲区中有数据,那么对象是有信号的,如果缓冲区为空,则对象是无信号的。
              </td>
            </tr>
            <tr> 
              <td width="22%">
                <p align="JUSTIFY">进程
              </td>
              <td width="78%">
                <p align="JUSTIFY">当调用CreateProcess建立进程时被创建。进程在运行时对象是无信号的,当进程终止时对象是有信号的。
              </td>
            </tr>
            <tr> 
              <td width="22%">
                <p align="JUSTIFY">线程
              </td>
              <td width="78%">
                <p align="JUSTIFY">当调用Createprocess、CreateThread或CreateRemoteThread函数创建新线程时被创建。在线程运行是对象是无信号的,在线程终止时则是有信号的。
              </td>
            </tr>
          </table>
          <p> </p>
          <p align="JUSTIFY"> </p>
          <p align="JUSTIFY">  当对象不再使用时,应该用CloseHandle函数关闭对象句柄。</p>
          <p align="JUSTIFY">  清单12.3是一个使用事件对象的简单例子,在该例中,假设主线程要读取共享缓冲区中的内容,而辅助线程负责向缓冲区中写入数据。两个线程使用了一个hEvent事件对象来同步。在用CreateEvent函数创建事件对象句柄时,指定该对象是一个自动重置事件,其初始状态为有信号的。当线程要读写缓冲区时,调用WaitForSingleObject函数无限等待hEvent信号。如果hEvent无信号,则说明另一线程正在访问缓冲区;如果有信号,则本线程可以访问缓冲区,WaitForSingleObject函数在返回后会自动把hEvent置成无信号的,这样在本线程读写缓冲区时别的线程不会同时访问。在完成读写操作后,调用SetEvent函数把hEvent置成有信号的,以使别的线程有机会访问共享缓冲区。</p>
          <b> 
          <p align="JUSTIFY"> </p>
          </b>
          <p align="JUSTIFY"><b>清单12.3 </b>使用事件对象的简单例子</p>
          <p align="JUSTIFY">HANDLE hEvent; //全局变量</p>
          <p align="JUSTIFY"> </p>
          <p align="JUSTIFY">//主线程</p>
          <p align="JUSTIFY">hEvent=CreateEvent(NULL, FALSE, TRUE, NULL);</p>
          <p align="JUSTIFY">if(hEvent= =NULL) return;</p>
          <p><b> </b></p>
          <b> 
          <p align="JUSTIFY">. . .</p>
          </b> 
          <p align="JUSTIFY">WaitForSingleObject(hEvent, INFINITE);</p>
          <p align="JUSTIFY">ReadFromBuf( );</p>
          <p align="JUSTIFY">SetEvent( hEvent );</p>
          <p><b> </b></p>
          <b> 
          <p align="JUSTIFY">. . .</p>
          </b> 
          <p align="JUSTIFY">CloseHandle( hEvent );</p>
          <p align="JUSTIFY"> </p>
          <p align="JUSTIFY"> </p>
          <p align="JUSTIFY">//辅助线程</p>
          <p align="JUSTIFY">UINT MyThreadProc( LPVOID pParam )</p>
          <p align="JUSTIFY">{</p>
          <p align="JUSTIFY"><b>. . .</b></p>
          <p align="JUSTIFY">WaitForSingleObject(hEvent, INFINITE);</p>
          <p align="JUSTIFY">WriteToBuf( );</p>
          <p align="JUSTIFY">SetEvent( hEvent );</p>
          <p align="JUSTIFY"><b>. . .</b></p>
          <p align="JUSTIFY"> <b></b>return 0; // 线程正常结束</p>
          <p align="JUSTIFY">}</p>
          <p align="JUSTIFY"><b></b><font color="#3973DE" face="Times New Roman">12.2.4 
            </font><font color="#3973DE">关键节和互锁变量访问</font></p>
          <p align="JUSTIFY">  关键节(Critical Seciton)与mutex的功能类似,但它只能由同一进程中的线程使用。关键节可以防止共享资源被同时访问。</p>
          <p align="JUSTIFY">  进程负责为关键节分配内存空间,关键节实际上是一个CRITICAL_SECTION型的变量,它一次只能被一个线程拥有。在线程使用关键节之前,必须调用InitializeCriticalSection函数将其初始化。如果线程中有一段关键的代码不希望被别的线程中断,那么可以调用EnterCriticalSection函数来申请关键节的所有权,在运行完关键代码后再用LeaveCriticalSection函数来释放所有权。如果在调用EnterCriticalSection时关键节对象已被另一个线程拥有,那么该函数将无限期等待所有权。</p>
          <p align="JUSTIFY">  利用互锁变量可以建立简单有效的同步机制。使用函数InterlockedIncrement和InterlockedDecrement可以增加或减少多个线程共享的一个32位变量的值,并且可以检查结果是否为0。线程不必担心会被其它线程中断而导致错误。如果变量位于共享内存中,那么不同进程中的线程也可以使用这种机制。</p>
          <div align="center">
            <center>
              <table border="0" cellpadding="0" cellspacing="0" width="615">
                <tr> 
                  <td><a href="chap12_1.htm">上一页</a></td>
                  <td>
                    <p align="right"><a href="chap12_3.htm">下一页</a>
                  </td>
                </tr>
              </table>
              <p><a href="http://www.cpcw.com">电脑报首页</a> <a href="../../index.htm">网络学院首页</a></p>
            </center>
          </div>
          <font size="5">
          <hr noshade color="#3973DE" size="1">
          </font>
          <p align="center"><font size="5"></font><font size="2" color="#000000">本教程由<a href="http://vcdynasty.yeah.net">Visual 
            C++王朝(Where programmers come together)</a>协助制作<br>
            未经许可,请勿以任何形式复制</font>
        </td>
      </tr>
    </table>
    </center>
</div>

</body>
</html>

⌨️ 快捷键说明

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