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

📄 csdn_文档中心_vc++多线程下内存操作的优化.htm

📁 csdn10年中间经典帖子
💻 HTM
📖 第 1 页 / 共 5 页
字号:
      <SCRIPT src="CSDN_文档中心_VC++多线程下内存操作的优化.files/microsoft.js"></SCRIPT>
    </TD>
    <TD align=middle width=620>
      <TABLE bgColor=#eeeeee border=0 cellPadding=0 cellSpacing=0 width=600>
        <TBODY>
        <TR bgColor=#ffffff>
          <TD align=middle height=10 width=50></TD>
          <TD align=right><A href="http://www.csdn.net/">CSDN</A> - <A 
            href="http://www.csdn.net/develop/">文档中心</A> - <FONT 
            color=#003399>Visual C++</FONT>&nbsp;&nbsp;&nbsp;&nbsp; </TD></TR>
        <TR>
          <TD align=middle height=5></TD>
          <TD align=middle width=500></TD></TR>
        <TR>
          <TD align=middle bgColor=#003399 height=10><FONT 
            color=#ffffff>标题</FONT></TD>
          <TD><B>&nbsp;&nbsp;&nbsp;&nbsp;VC++多线程下内存操作的优化</B>&nbsp;&nbsp;&nbsp;&nbsp;zdg(收藏) 
          </TD></TR>
        <TR>
          <TD align=middle height=5></TD>
          <TD align=middle width=500></TD></TR>
        <TR>
          <TD align=middle bgColor=#003399><FONT color=#ffffff>关键字</FONT></TD>
          <TD width=500>&nbsp;&nbsp;&nbsp;&nbsp;VC++多线程下内存操作的优化</TD></TR>
        <TR>
          <TD align=middle height=5></TD>
          <TD align=middle width=500></TD></TR></TBODY></TABLE><!--文章说明信息结束//-->
      <TABLE border=0 width=600>
        <TBODY>
        <TR>
          <TD align=left><BR>
            <P align=right class=MsoNormal style="TEXT-ALIGN: right"><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">作者/李红亚</SPAN><SPAN 
            lang=EN-US><?xml:namespace prefix = o ns = 
            "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></P>
            <P class=MsoNormal><SPAN lang=EN-US>&nbsp;<o:p></o:p></SPAN></P>
            <P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">许多程序员发现用</SPAN><SPAN 
            lang=EN-US>VC++</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">编写的程序在多处理器的电脑上运行会变得很慢,这种情况多是由于多个线程争用同一个资源引起的。对于用</SPAN><SPAN 
            lang=EN-US>VC++</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">编写的程序,问题出在</SPAN><SPAN 
            lang=EN-US>VC++</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的内存管理的具体实现上。以下通过对这个问题的解释,提供一个简便的解决方法,使得这种程序在多处理器下避免出现运行瓶颈。这种方法在没有</SPAN><SPAN 
            lang=EN-US>VC++</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">程序的源代码时也能用。</SPAN><SPAN 
            lang=EN-US><o:p></o:p></SPAN></P>
            <P class=MsoNormal><B><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">问题</SPAN><SPAN 
            lang=EN-US><o:p></o:p></SPAN></B></P>
            <P class=MsoNormal><SPAN lang=EN-US><SPAN 
            style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>C</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</SPAN><SPAN 
            lang=EN-US>C++</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">运行库提供了对于堆内存进行管理的函数:</SPAN><SPAN 
            lang=EN-US>C</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">提供的是</SPAN><SPAN 
            lang=EN-US>malloc()</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</SPAN><SPAN 
            lang=EN-US>free()</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、</SPAN><SPAN 
            lang=EN-US>C++</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">提供的是</SPAN><SPAN 
            lang=EN-US>new</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</SPAN><SPAN 
            lang=EN-US>delete</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。无论是通过</SPAN><SPAN 
            lang=EN-US>malloc()</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">还是</SPAN><SPAN 
            lang=EN-US>new</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">申请内存,这些函数都是在堆内存中寻找一个未用的块,并且块的大小要大于所申请的大小。如果没有足够大的未用的内存块,运行时间库就会向操作系统请求新的页。页是虚拟内存管理器进行操作的单位,在基于</SPAN><SPAN 
            lang=EN-US>Intel</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的处理器的</SPAN><SPAN 
            lang=EN-US>NT</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">平台下,一般是</SPAN><SPAN 
            lang=EN-US>4,096</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">字节。当你调用</SPAN><SPAN 
            lang=EN-US>free()</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">或</SPAN><SPAN 
            lang=EN-US>delete</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">释放内存时,这些内存块就返还给堆,供以后申请内存时用。</SPAN><SPAN 
            lang=EN-US><o:p></o:p></SPAN></P>
            <P class=MsoNormal><BR clear=all style="mso-ignore: vglayout"><SPAN 
            lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; 
            </SPAN></SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这些操作看起来不太起眼,但是问题的关键。问题就发生在当多个线程几乎同申请内存时,这通常发生在多处理器的系统上。但即使在一个单处理器的系统上,如果线程在错误的时间被调度,也可能发生这个问题。</SPAN><SPAN 
            lang=EN-US><o:p></o:p></SPAN></P>
            <P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">考虑处于同一进程中的两个线程,线程</SPAN><SPAN 
            lang=EN-US>1</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在申请</SPAN><SPAN 
            lang=EN-US>1,024</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">字节的内存的同时,运行于另外一个处理器的线程</SPAN><SPAN 
            lang=EN-US>2</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">申请</SPAN><SPAN 
            lang=EN-US>256</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">字节内存。内存管理器发现一个未用的内存块用于线程</SPAN><SPAN 
            lang=EN-US>1</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">,同时同一个函数发现了同一块内存用于线程</SPAN><SPAN 
            lang=EN-US>2</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。如果两个线程同时更新内部数据结构,记录所申请的内存及其大小,堆内存就会产生冲突。即使申请内存的函数者成功返回,两个线程都确信自己拥有那块内存,这个程序也会产生错误,这只是个时间问题。</SPAN><SPAN 
            lang=EN-US><o:p></o:p></SPAN></P>
            <P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">产生这种情况称为争用,是编写多线程程序的最大问题。解决这个问题的关键是要用一个锁定机制来保护内存管理器的这些函数,锁定机制保证运行相同代码的多个线程互斥地进行,如果一个线程正运行受保护的代码,则其他的线程都必须等待,这种解决方法也称作序列化。</SPAN><SPAN 
            lang=EN-US><o:p></o:p></SPAN></P>
            <P class=MsoNormal><SPAN lang=EN-US><SPAN 
            style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>NT</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">提供了一些锁定机制的实现方法。</SPAN><SPAN 
            lang=EN-US>CreateMutex()</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">创建一个系统范围的锁定对象,但这种方法的效率最低;</SPAN><SPAN 
            lang=EN-US>InitializeCriticalSection()</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">创建的</SPAN><SPAN 
            lang=EN-US>critical section</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">相对效率就要高许多;要得到更好的性能,可以用具有</SPAN><SPAN 
            lang=EN-US>service pack 3</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</SPAN><SPAN 
            lang=EN-US>NT 4</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</SPAN><SPAN 
            lang=EN-US>spin lock</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">,更详细的信息可以参考</SPAN><SPAN 
            lang=EN-US>VC++</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">帮助中的</SPAN><SPAN 
            lang=EN-US>InitializeCriticalSectionAndSpinCount()</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数的说明。有趣的是,虽然帮助文件中说</SPAN><SPAN 
            lang=EN-US>spin lock</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用于</SPAN><SPAN 
            lang=EN-US>NT</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的堆管理器</SPAN><SPAN 
            lang=EN-US>(HeapAlloc()</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">系列的函数</SPAN><SPAN 
            lang=EN-US>)</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">,</SPAN><SPAN 
            lang=EN-US>VC++</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">运行库的堆管理函数并没有用</SPAN><SPAN 
            lang=EN-US>spin lock</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">来同步对堆的存取。如果查看</SPAN><SPAN 
            lang=EN-US>VC++</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">运行库的堆管理函数的源程序,会发现是用一个</SPAN><SPAN 
            lang=EN-US>critical section</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用于全部的内存操作。如果可以在</SPAN><SPAN 
            lang=EN-US>VC++</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">运行库中用</SPAN><SPAN 
            lang=EN-US>HeapAlloc()</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">,而不是其自己的堆管理函数,将会因为使用的是</SPAN><SPAN 
            lang=EN-US>spin lock</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">而不是</SPAN><SPAN 
            lang=EN-US>critical section</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">而得到速度优化。</SPAN><SPAN 
            lang=EN-US><o:p></o:p></SPAN></P>
            <P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">通过使用</SPAN><SPAN 
            lang=EN-US>critical section</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">同步对堆的存取,</SPAN><SPAN 
            lang=EN-US>VC++</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">运行库可以安全地让多个线程申请和释放内存。然而,由于内存的争用,这种方法会引起性能的下降。如果一个线程存取另外一个线程正在使用的堆时,前一个线程就需要等待,并丧失自己的时间片,切换到其他的线程。线程的切换在</SPAN><SPAN 
            lang=EN-US>NT</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">下是相当费时的,因为其占用线程的时间片的一个小的百分比。如果有多个线程同时要存取同一个堆,会引起更多的线程切换,足够引起极大的性能损失。</SPAN><SPAN 
            lang=EN-US><o:p></o:p></SPAN></P>
            <P class=MsoNormal><SPAN lang=EN-US>&nbsp;<o:p></o:p></SPAN></P>
            <P class=MsoNormal><B><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">现象</SPAN><SPAN 
            lang=EN-US><o:p></o:p></SPAN></B></P>
            <P class=MsoNormal><SPAN lang=EN-US><SPAN 
            style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如何发现多处理器系统存在这种性能损失?有一个简便的方法,打开“管理工具”中的“性能”监视器,在系统组中添加一个上下文切换</SPAN><SPAN 
            lang=EN-US>/</SPAN><SPAN 
            style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">秒计数,然后运行想要测试的多线程程序,并且在进程组中添加该进程的处理器时间计数,这样就可以得到处理器在高负荷下要发生多少次上下文切换。</SPAN><SPAN 

⌨️ 快捷键说明

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