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

📄 chap12_2.htm

📁 MFC开发基础教程
💻 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>
</head>

<body link="#3973DE" alink="#3973DE">
<font SIZE="5"><b><div align="center"><center>

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

⌨️ 快捷键说明

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