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

📄 chap12_2.htm

📁 VC++教程电子图书
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 3.0">
<title>12.2 线程的同步</title>
<link rel="stylesheet" href="../../../cpcw.css"></head>

<body link="#3973DE" alink="#3973DE" background="../../bg.gif">
<div align="center"><center>
    <table width="85%" border="0">
      <tr bgcolor="#FFFFFF"> 
        <td> 
          <div align="center">
            <center>
            </center>
          </div>
          <p align="CENTER"><b><font color="red"><font face="Times New Roman">12.2 
            </font>线程的同步</font></b></p>
          <p align="CENTER"> </p>
          <p align="JUSTIFY">  多线程的使用会产生一些新的问题,主要是如何保证线程的同步执行。多线程应用程序需要使用同步对象和等待函数来实现同步。</p>
          <p align="JUSTIFY"> <b></b><font color="#3973DE" face="Times New Roman">12.2.1 
            </font><font color="#3973DE">为什么需要同步</font></p>
          <p align="JUSTIFY">  由于同一进程的所有线程共享进程的虚拟地址空间,并且线程的中断是汇编语言级的,所以可能会发生两个线程同时访问同一个对象(包括全局变量、共享资源、API函数和MFC对象等)的情况,这有可能导致程序错误。例如,如果一个线程在未完成对某一大尺寸全局变量的读操作时,另一个线程又对该变量进行了写操作,那么第一个线程读入的变量值可能是一种修改过程中的不稳定值。</p>
          <p align="JUSTIFY">  属于不同进程的线程在同时访问同一内存区域或共享资源时,也会存在同样的问题。</p>
          <p align="JUSTIFY">  因此,在多线程应用程序中,常常需要采取一些措施来同步线程的执行。需要同步的情况包括以下几种:</p>
          <blockquote> 
            <blockquote> 
              <p align="JUSTIFY">在多个线程同时访问同一对象时,可能产生错误。例如,如果当一个线程正在读取一个至关重要的共享缓冲区时,另一个线程向该缓冲区写入数据,那么程序的运行结果就可能出错。程序应该尽量避免多个线程同时访问同一个缓冲区或系统资源。</p>
              <p align="JUSTIFY">在Windows 95环境下编写多线程应用程序还需要考虑重入问题。Windows NT是真正的32位操作系统,它解决了系统重入问题。而Windows 
                95由于继承了Windows 3.x的部分16位代码,没能够解决重入问题。这意味着在Windows 95中两个线程不能同时执行某个系统功能,否则有可能造成程序错误,甚至会造成系统崩溃。应用程序应该尽量避免发生两个以上的线程同时调用同一个Windows 
                API函数的情况。</p>
              <p align="JUSTIFY">由于大小和性能方面的原因,MFC对象在对象级不是线程安全的,只有在类级才是。也就是说,两个线程可以安全地使用两个不同的CString对象,但同时使用同一个CString对象就可能产生问题。如果必须使用同一个对象,那么应该采取适当的同步措施。</p>
              <p align="JUSTIFY">多个线程之间需要协调运行。例如,如果第二个线程需要等待第一个线程完成到某一步时才能运行,那么该线程应该暂时挂起以减少对CPU的占用时间,提高程序的执行效率。当第一个线程完成了相应的步骤后,应该发出某种信号来激活第二个线程。</p>
            </blockquote>
          </blockquote>
          <p><b> </b></p>
          <p align="JUSTIFY"> <b></b><font color="#3973DE" face="Times New Roman">12.2.2 
            </font><font color="#3973DE">等待函数</font></p>
          <p align="JUSTIFY">  Win32 API提供了一组能使线程阻塞其自身执行的等待函数。这些函数只有在作为其参数的一个或多个同步对象(见下小节)产生信号时才会返回。在超过规定的等待时间后,不管有无信号,函数也都会返回。在等待函数未返回时,线程处于等待状态,此时线程只消耗很少的CPU时间。</p>
          <p align="JUSTIFY">  使用等待函数即可以保证线程的同步,又可以提高程序的运行效率。最常用的等待函数是WaitForSingleObject,该函数的声明为:</p>
          <blockquote> 
            <blockquote> 
              <blockquote> 
                <p align="JUSTIFY">DWORD WaitForSingleObject(HANDLE hHandle, DWORD 
                  dwMilliseconds);</p>
              </blockquote>
            </blockquote>
          </blockquote>
          <p>  参数hHandle是同步对象的句柄。参数dwMilliseconds是以毫秒为单位的超时间隔,如果该参数为0,那么函数就测试同步对象的状态并立即返回,如果该参数为INFINITE,则超时间隔是无限的。函数的返回值在表12.1中列出。</p>
          <p align="JUSTIFY"><b> </b></p>
          <b> 
          <p align="CENTER">表12.1 WaitForSingleObject的返回值</p>
          </b> 
          <table border="1" cellspacing="1" cellpadding="1" width="579">
            <tr> 
              <td width="27%"><b>
                <p align="JUSTIFY">返回值
                </b></td>
              <td width="73%"><b>
                <p align="JUSTIFY">含义
                </b></td>
            </tr>
            <tr> 
              <td width="27%">
                <p align="JUSTIFY">WAIT_FAILED
              </td>
              <td width="73%">
                <p align="JUSTIFY">函数失败
              </td>
            </tr>
            <tr> 
              <td width="27%">
                <p align="JUSTIFY">WAIT_OBJECT_0
              </td>
              <td width="73%">
                <p align="JUSTIFY">指定的同步对象处于有信号的状态
              </td>
            </tr>
            <tr> 
              <td width="27%">
                <p align="JUSTIFY">WAIT_ABANDONED
              </td>
              <td width="73%">
                <p align="JUSTIFY">拥有一个mutex的线程已经中断了,但未释放该MUTEX
              </td>
            </tr>
            <tr> 
              <td width="27%">
                <p align="JUSTIFY">WAIT_TIMEOUT
              </td>
              <td width="73%">
                <p align="JUSTIFY">超时返回,并且同步对象无信号
              </td>
            </tr>
          </table>
          <p> </p>
          <p align="JUSTIFY"> </p>
          <p align="JUSTIFY">函数WaitForMultipleObjects可以同时监测多个同步对象,该函数的声明为:</p>
          <blockquote> 
            <blockquote> 
              <blockquote> 
                <p align="JUSTIFY">DWORD WaitForMultipleObjects(DWORD nCount, 
                  CONST HANDLE *lpHandles, BOOL bWaitAll, DWORD dwMilliseconds 
                  );</p>
              </blockquote>
            </blockquote>
          </blockquote>
          <p> </p>
          <p align="JUSTIFY">  参数nCount是句柄数组中句柄的数目。lpHandles代表一个句柄数组。bWaitAll说明了等待类型,如果为TRUE,那么函数在所有对象都有信号后才返回,如果为FALSE,则只要有一个对象变成有信号的,函数就返回。函数的返回值在表12.2中列出。参数dwMilliseconds是以毫秒为单位的超时间隔,如果该参数为0,那么函数就测试同步对象的状态并立即返回,如果该参数为INFINITE,则超时间隔是无限的。</p>
          <p align="JUSTIFY"><b> </b></p>
          <b> 
          <p align="CENTER">表12.2 WaitForMultipleObjects的返回值</p>
          </b> 
          <table border="1" cellspacing="1" cellpadding="1" width="579">
            <tr> 
              <td width="35%"><b>
                <p align="JUSTIFY">返回值
                </b></td>
              <td width="65%"><b>
                <p align="JUSTIFY">说明
                </b></td>
            </tr>
            <tr> 
              <td width="35%">
                <p align="JUSTIFY">WAIT_OBJECT_0到WAIT_ OBJECT_0+nCount-1
              </td>
              <td width="65%">
                <p align="JUSTIFY">若bWaitAll为TRUE,则返回值表明所有对象都是有信号的。如果bWaitAll为FALSE,则返回值减去WAIT_OBJECT_0就是数组中有信号对象的最小索引。
              </td>
            </tr>
            <tr> 
              <td width="35%">
                <p align="JUSTIFY">WAIT_ABANDONED_0到WAIT_ ABANDONED_ 0+nCount-1
              </td>
              <td width="65%">
                <p align="JUSTIFY">若bWaitAll为TRUE,则返回值表明所有对象都有信号,但有一个mutex被放弃了。若bWaitAll为FALSE,则返回值减去WAIT_ABANDONED_0就是被放弃mutex在对象数组中的索引。
              </td>

⌨️ 快捷键说明

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