﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-局部变量的作用域-随笔分类-原创</title><link>http://www.cppblog.com/localvar/category/15392.html</link><description>&lt;font color="yellow" size=4&gt;本站关闭评论功能，如需评论请移步：&lt;a href="http://zbm.xuanwo.tk/"&gt;http://zbm.xuanwo.tk/&lt;/a&gt;&lt;/font&gt;</description><language>zh-cn</language><lastBuildDate>Mon, 09 May 2011 18:42:11 GMT</lastBuildDate><pubDate>Mon, 09 May 2011 18:42:11 GMT</pubDate><ttl>60</ttl><item><title>检测Lua脚本中的死循环</title><link>http://www.cppblog.com/localvar/archive/2011/05/07/145908.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Sat, 07 May 2011 11:18:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2011/05/07/145908.html</guid><description><![CDATA[<p>评论请移步：<a href="http://zbm.xuanwo.tk/2011/05/lua-deadloop.html">http://zbm.xuanwo.tk/2011/05/lua-deadloop.html</a><a href="http://vckbase.com/bbs"></a></p>
<a href="http://vckbase.com/bbs"></a>
<p><a href="http://vckbase.com/bbs">论坛</a>上有人问，所以把以前做的东西拿出来秀一下。</p>
<p>Lua是一门小巧精致的语言，特别适用于嵌入其它的程序为它们提供脚本支持。不过脚本通常是用户编写的，很有可能出现死循环，虽说这是用户的问题，但却会造成我们的宿主程序死掉。所以检测用户脚本中的死循环并中止这段脚本的运行就显得非常重要了。</p>
<p>可是，一个现实的问题是死循环并不好检测，一些隐藏较深的死循环连人都很难找出来，更不用说让机器去找了。所以实际采用的方案多是检测脚本的执行时间，如果超过一定的限度，就认为里面有死循环，我下面的例子也是用的这种方法。</p>
<p>以下是几个相关的全局变量（我是喜欢把C++当C用的程序员，C++的忠实粉丝请忍耐一下:)）的定义。</p>
<div style="PADDING-RIGHT: 5px; PADDING-LEFT: 4px; FONT-SIZE: 13px; BORDER-LEFT-COLOR: rgb(204,204,204); PADDING-BOTTOM: 4px; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BACKGROUND-COLOR: rgb(238,238,238)"><span style="COLOR: #008080">1</span>&nbsp;<span style="COLOR: #000000">lua_State</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;g_lua&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;NULL;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;lua脚本引擎</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">2</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #0000ff">volatile</span><span style="COLOR: #000000">&nbsp;unsigned&nbsp;g_begin&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;脚本开始执行的时间</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">3</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #0000ff">volatile</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">long</span><span style="COLOR: #000000">&nbsp;g_counter&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;脚本执行计数,&nbsp;用于判断执行超时</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">4</span>&nbsp;<span style="COLOR: #0000ff">volatile</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000"></span><span style="COLOR: #0000ff">long</span><span style="COLOR: #000000">&nbsp;g_check&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;进行超时检查时的执行计数</span></div>
<p>run_user_script用来执行用户脚本，它首先通过GetTickCount把当前的时间记录到g_begin中去。然后将g_counter加一，在执行完用户脚本后再将其加一，这样就可以保证执行用户脚本时它是个奇数，而不执行时是偶数，检测脚本超时的代码可以籍此来判断当前是否在执行用户脚本。还要注意调用用户脚本要使用lua_pcall而不是lua_call，因为我们中止脚本的执行会产生一个Lua中的&#8220;错误&#8221;，在C/C++中它是一个异常，只有用lua_pcall才能保证这个错误被Lua脚本引擎正确处理。</p>
<div style="PADDING-RIGHT: 5px; PADDING-LEFT: 4px; FONT-SIZE: 13px; BORDER-LEFT-COLOR: rgb(204,204,204); PADDING-BOTTOM: 4px; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BACKGROUND-COLOR: rgb(238,238,238)"><span style="COLOR: #008080">1</span>&nbsp;<span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;run_user_script(&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;nargs,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;nresults,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;errfunc&nbsp;)<br></span><span style="COLOR: #008080">2</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">3</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;g_begin&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;GetTickCount();<br></span><span style="COLOR: #008080">4</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;_InterlockedIncrement(&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">g_counter&nbsp;);<br></span><span style="COLOR: #008080">5</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;err&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;lua_pcall(&nbsp;g_lua,&nbsp;nargs,&nbsp;nresults,&nbsp;errfunc&nbsp;);<br></span><span style="COLOR: #008080">6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;_InterlockedIncrement(&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">g_counter&nbsp;);<br></span><span style="COLOR: #008080">7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;err;<br></span><span style="COLOR: #008080">8</span>&nbsp;<span style="COLOR: #000000">}</span></div>
<p>下面的check_script_timeout用来检测脚本超时，需要在另外一个线程中周期性的调用，原因我想就不用解释了吧。它首先检查是否在执行用户脚本，或者是否已经让当前执行的用户脚本中止过。然后看这段脚本执行了多长时间，超过限度就把当前脚本计数记录到g_check中去，并通过lua_sethook设置一个钩子函数timeout_break，这个钩子函数会在用户脚本执行时被调用。</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;check_script_timeout()<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">long</span><span style="COLOR: #000000">&nbsp;counter&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;g_counter;<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">&nbsp;<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;没有执行用户脚本,&nbsp;不检查超时</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;(counter&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0x00000001</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)<br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000">&nbsp;<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;已经让当前执行的用户脚本中止了</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;g_check&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;counter&nbsp;)<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000">&nbsp;<br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;如果执行时间超过了设置的超时时间(这里是1秒),&nbsp;终止它</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;GetTickCount()&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">&nbsp;g_begin&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">&nbsp;)<br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_check&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;counter;<br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;mask&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;LUA_MASKCALL&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;LUA_MASKRET&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;LUA_MASKLINE&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;LUA_MASKCOUNT;<br></span><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lua_sethook(&nbsp;g_lua,&nbsp;timeout_break,&nbsp;mask,&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #000000">}</span></div>
<p>最后就是那个钩子函数了，它首先把钩子去掉，因为这个钩子只要执行一次就行了。由于设置钩子和执行钩子是在不同的线程中，并且钩子从设置到执行需要一定的时间，所以它要通过对比g_check和g_counter来判断是否还在运行判断超时所执行的那段脚本，不是就什么也不做，是就通过luaL_error产生一个错误，并中止脚本的执行，而这个错误最终会被run_user_script中的lua_pcall捕获。</p>
<div style="PADDING-RIGHT: 5px; PADDING-LEFT: 4px; FONT-SIZE: 13px; BORDER-LEFT-COLOR: rgb(204,204,204); PADDING-BOTTOM: 4px; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BACKGROUND-COLOR: rgb(238,238,238)"><span style="COLOR: #008080">1</span>&nbsp;<span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;timeout_break(&nbsp;lua_State</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;L,&nbsp;lua_Debug</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;ar&nbsp;)<br></span><span style="COLOR: #008080">2</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">3</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;lua_sethook(&nbsp;L,&nbsp;NULL,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;);<br></span><span style="COLOR: #008080">4</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;钩子从设置到执行,&nbsp;需要一段时间,&nbsp;所以要检测是否仍在执行那个超时的脚本</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">5</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;g_check&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;g_counter&nbsp;)<br></span><span style="COLOR: #008080">6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;luaL_error(&nbsp;L,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">script&nbsp;timeout.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;);<br></span><span style="COLOR: #008080">7</span>&nbsp;<span style="COLOR: #000000">}</span></div>
<p>上面的检测使用了两个线程，其实在一个线程中也可以做到，并且更简单。但那样会导致钩子函数频繁执行，影响效率，如果对性能没什么要求的话，也可以采用。</p><img src ="http://www.cppblog.com/localvar/aggbug/145908.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2011-05-07 19:18 <a href="http://www.cppblog.com/localvar/archive/2011/05/07/145908.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多线程中的单件模式</title><link>http://www.cppblog.com/localvar/archive/2011/02/11/139892.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Fri, 11 Feb 2011 06:07:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2011/02/11/139892.html</guid><description><![CDATA[<p>评论请移步：<a href="http://zbm.xuanwo.tk/2011/02/singleton-in-multithread.html"><u><font color=#810081>http://zbm.xuanwo.tk/2011/02/singleton-in-multithread.html</font></u></a></p>
<p>单件模式可能是所有设计模式中最简单的一个了，但在C++中，尤其是还要支持多线程的话，要想写一个正确的实现却并不容易，不信请看：</p>
<pre class=brush:cpp>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;CSingleton<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">&nbsp;CSingleton()<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;_tprintf(&nbsp;_T(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">CSingleton::Constructor:&nbsp;Before&nbsp;Sleep\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)&nbsp;);<br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;Sleep(&nbsp;</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">&nbsp;);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;不会改变逻辑,&nbsp;但增大了问题出现的概率</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;_tprintf(&nbsp;_T(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">CSingleton::Constructor:&nbsp;After&nbsp;Sleep\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)&nbsp;);<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">&nbsp;}<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;DoSomeThing()<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">&nbsp;{<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;_tprintf(&nbsp;_T(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">CSingleton::DoSomeThing\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)&nbsp;);<br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000">&nbsp;}<br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;CSingleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;GetInstance()<br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #000000">&nbsp;{<br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;CSingleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;p&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;NULL;<br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;p&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;NULL&nbsp;)<br></span><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;p&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;CSingleton();<br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;p;<br></span><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #000000">&nbsp;}<br></span><span style="COLOR: #008080">21</span>&nbsp;<span style="COLOR: #000000">};<br></span><span style="COLOR: #008080">22</span>&nbsp;<span style="COLOR: #000000">unsigned&nbsp;__stdcall&nbsp;thread(&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;)<br></span><span style="COLOR: #008080">23</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">24</span>&nbsp;<span style="COLOR: #000000">&nbsp;CSingleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;p&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;CSingleton::GetInstance();<br></span><span style="COLOR: #008080">25</span>&nbsp;<span style="COLOR: #000000">&nbsp;p</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">DoSomeThing();<br></span><span style="COLOR: #008080">26</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">27</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">28</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;_tmain(&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;_TCHAR</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[]&nbsp;)<br></span><span style="COLOR: #008080">29</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">30</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;i&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">;&nbsp;</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">i&nbsp;)<br></span><span style="COLOR: #008080">31</span>&nbsp;<span style="COLOR: #000000">&nbsp;{<br></span><span style="COLOR: #008080">32</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;uintptr_t&nbsp;t&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;_beginthreadex(&nbsp;NULL,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;thread,&nbsp;NULL,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;NULL&nbsp;);<br></span><span style="COLOR: #008080">33</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;CloseHandle(&nbsp;(HANDLE)t&nbsp;);<br></span><span style="COLOR: #008080">34</span>&nbsp;<span style="COLOR: #000000">&nbsp;}<br></span><span style="COLOR: #008080">35</span>&nbsp;<span style="COLOR: #000000">&nbsp;_getch();<br></span><span style="COLOR: #008080">36</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">37</span>&nbsp;<span style="COLOR: #000000">}</span></div>
</pre>
<p>上面的单件实现在单线程中肯定是正确的，不过在多线程中的输出却如下：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">1</span>&nbsp;<span style="COLOR: #000000">CSingleton::Constructor:&nbsp;Before&nbsp;Sleep<br></span><span style="COLOR: #008080">2</span>&nbsp;<span style="COLOR: #000000">CSingleton::Constructor:&nbsp;Before&nbsp;Sleep<br></span><span style="COLOR: #008080">3</span>&nbsp;<span style="COLOR: #000000">CSingleton::Constructor:&nbsp;Before&nbsp;Sleep<br></span><span style="COLOR: #008080">4</span>&nbsp;<span style="COLOR: #000000">CSingleton::Constructor:&nbsp;After&nbsp;Sleep<br></span><span style="COLOR: #008080">5</span>&nbsp;<span style="COLOR: #000000">CSingleton::DoSomeThing<br></span><span style="COLOR: #008080">6</span>&nbsp;<span style="COLOR: #000000">CSingleton::Constructor:&nbsp;After&nbsp;Sleep<br></span><span style="COLOR: #008080">7</span>&nbsp;<span style="COLOR: #000000">CSingleton::DoSomeThing<br></span><span style="COLOR: #008080">8</span>&nbsp;<span style="COLOR: #000000">CSingleton::Constructor:&nbsp;After&nbsp;Sleep<br></span><span style="COLOR: #008080">9</span>&nbsp;<span style="COLOR: #000000">CSingleton::DoSomeThing</span></div>
<p>很明显，虽然我们想做个单件，但它却出现了多个实例（或一个实例被初始化了多次）。其原因是我们的实现根本没有考虑多线程，那下面的代码把创建实例的部分锁住是不是就行了呢？</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;CCriSec&nbsp;:&nbsp;CRITICAL_SECTION<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">&nbsp;CCriSec()<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;Sleep(&nbsp;</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">&nbsp;);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;增大出问题的概率,&nbsp;但不改变逻辑</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;InitializeCriticalSection(&nbsp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&nbsp;);<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000">&nbsp;}<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">CCriSec()&nbsp;{&nbsp;DeleteCriticalSection(&nbsp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&nbsp;);&nbsp;}<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;Enter()<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">&nbsp;{<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;EnterCriticalSection(&nbsp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&nbsp;);<br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000">&nbsp;}<br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;Leave()&nbsp;{&nbsp;LeaveCriticalSection(&nbsp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&nbsp;);&nbsp;}<br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #000000">};<br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"></span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;CSingleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;GetInstance()<br></span><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;CSingleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;p&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;NULL;<br></span><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;CCriSec&nbsp;</span><span style="COLOR: #0000ff">lock</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">21</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">lock</span><span style="COLOR: #000000">.Enter();<br></span><span style="COLOR: #008080">22</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;p&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;NULL&nbsp;)<br></span><span style="COLOR: #008080">23</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;p&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;CSingleton();<br></span><span style="COLOR: #008080">24</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">lock</span><span style="COLOR: #000000">.Leave();<br></span><span style="COLOR: #008080">25</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;p;<br></span><span style="COLOR: #008080">26</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">27</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"></span></div>
<p>运行一下，不管输出是什么，程序崩溃了。分析一下可以发现，这个例子中的我们确实控制好了对CSingleton实例的初始化，但这种控制却依赖于另一个静态变量（CCriSec的实例）的初始化，而这个新的静态变量导致了程序的崩溃，也就是说我们在解决问题的同时引入了新的问题。而且，在这种情况下，就算再引入多少个新的临界区也无济于事，因为对最外层的临界区的初始化总会有问题。</p>
<p>上面的例子的问题在于CCriSec是一种复杂的数据类型，所以对它的初始化总要到运行时才能完成，如果用整数这样简单的、能在编译期完成初始化的数据类型来做是不是可以呢？</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">1</span>&nbsp;<span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;CSingleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;GetInstance()<br></span><span style="COLOR: #008080">2</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">3</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;CSingleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;p&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;NULL;<br></span><span style="COLOR: #008080">4</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">volatile</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">long</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">lock</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">5</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;InterlockedCompareExchange(&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #0000ff">lock</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)<br></span><span style="COLOR: #008080">6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;p&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;CSingleton();<br></span><span style="COLOR: #008080">7</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;p;<br></span><span style="COLOR: #008080">8</span>&nbsp;<span style="COLOR: #000000">}</span></div>
<p>看起来好像没有问题，但运行一下却是下面的输出：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">1</span>&nbsp;<span style="COLOR: #000000">CSingleton::Constructor:&nbsp;Before&nbsp;Sleep<br></span><span style="COLOR: #008080">2</span>&nbsp;<span style="COLOR: #000000">CSingleton::DoSomeThing<br></span><span style="COLOR: #008080">3</span>&nbsp;<span style="COLOR: #000000">CSingleton::DoSomeThing<br></span><span style="COLOR: #008080">4</span>&nbsp;<span style="COLOR: #000000">CSingleton::Constructor:&nbsp;After&nbsp;Sleep<br></span><span style="COLOR: #008080">5</span>&nbsp;<span style="COLOR: #000000">CSingleton::DoSomeThing</span></div>
<p>也就是说DoSomeThing在构造函数返回之前已经被调用了，这显然也是错误的。其原因是我们忽略了&#8220;对象的创建时需要时间的&#8221;，把这个问题也修正一下，就是最终的正确实现了：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;CSingleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;GetInstance()<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;CSingleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;p&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;NULL;<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">volatile</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">long</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">lock</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;InterlockedCompareExchange(&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #0000ff">lock</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000">&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(&nbsp;</span><span style="COLOR: #0000ff">lock</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">&nbsp;)&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;等待对象创建完成</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;Sleep(&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;);<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;p;<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000">&nbsp;}<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">&nbsp;p&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;CSingleton();<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">lock</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;p;<br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #000000">}</span></div>
<p>本文采用的单件实现是函数内的静态变量，如果你采用其它方式，也会有类似问题。其实在我看来，单件模式是一个看起来简单、做对了很难（上面演示的是多线程中的问题，在具体的实践中还会遇到很多其他问题）、同时又没有太多实用价值的东西。</p>
<p>另外，从Windows Vista开始，微软提供了一种多线程下对象初始化的方法，有兴趣的可以中搜一下&#8220;INITONCE&#8221;，个人认为INITONCE有点完美的过头了，真正好玩又有用的是与它同时出现的&#8220;条件变量（condition variable）&#8221;。</p>
<img src ="http://www.cppblog.com/localvar/aggbug/139892.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2011-02-11 14:07 <a href="http://www.cppblog.com/localvar/archive/2011/02/11/139892.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编写可维护的代码(二)</title><link>http://www.cppblog.com/localvar/archive/2010/12/16/136645.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Thu, 16 Dec 2010 08:24:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2010/12/16/136645.html</guid><description><![CDATA[<p>假如一个系统中有多个模块，不妨命名为Module1, Module2, Module3......, 毫无疑问这个系统的启动过程中需要初始化所有这些模块, 而退出时要销毁它们, 那应该用下面哪种方法来完成这个任务呢?</p>
<div>A. 让这些模块都支持一个IModule, 然后定义一个IModule*类型的数组, 把这些模块的指针都加进去:
<table style="BORDER-COLLAPSE: collapse" borderColor=#999999 cellSpacing=0 cellPadding=0 width="55%" bgColor=#f1f1f1 border=1>
    <tbody>
        <tr>
            <td>
            <p style="MARGIN: 5px; LINE-HEIGHT: 150%"><code><span style="COLOR: #000000"><font face=NSimsun>IModule<span style="COLOR: #0000cc">*</span> modules<span style="COLOR: #0000cc">[</span><span style="COLOR: #0000cc">]</span> <span style="COLOR: #0000cc">=</span> <span style="COLOR: #0000cc">{</span><span style="COLOR: #0000cc">&amp;</span>Module1<span style="COLOR: #0000cc">,</span> <span style="COLOR: #0000cc">&amp;</span>Module2<span style="COLOR: #0000cc">,</span> <span style="COLOR: #0000cc">&amp;</span>Module3<span style="COLOR: #0000cc">,</span> <span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">}</span><span style="COLOR: #0000cc">;</span><br></font><font face=NSimsun><span style="COLOR: #ff9900"></span></font></span></code></p>
            <p style="MARGIN: 5px; LINE-HEIGHT: 150%"><code><span style="COLOR: #000000"><font face=NSimsun><span style="COLOR: #ff9900">// 初始化时:<br></span><span style="COLOR: #0000ff">for</span><span style="COLOR: #0000cc">(</span><span style="COLOR: #0000ff">int</span> i <span style="COLOR: #0000cc">=</span> 0<span style="COLOR: #0000cc">;</span> i <span style="COLOR: #0000cc">&lt;</span> <span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #0000cc">(</span>modules<span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">/</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #0000cc">(</span>modules<span style="COLOR: #0000cc">[</span>0<span style="COLOR: #0000cc">]</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span> <span style="COLOR: #0000cc">+</span><span style="COLOR: #0000cc">+</span>i<span style="COLOR: #0000cc">)</span><br>&nbsp;modules<span style="COLOR: #0000cc">[</span>i<span style="COLOR: #0000cc">]</span><span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>Init<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br></font><font face=NSimsun><span style="COLOR: #ff9900"></span></font></span></code></p>
            <p style="MARGIN: 5px; LINE-HEIGHT: 150%"><code><span style="COLOR: #000000"><font face=NSimsun><span style="COLOR: #ff9900">// 退出时:<br></span><span style="COLOR: #0000ff">for</span><span style="COLOR: #0000cc">(</span><span style="COLOR: #0000ff">int</span> i <span style="COLOR: #0000cc">=</span> <span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #0000cc">(</span>modules<span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">/</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #0000cc">(</span>modules<span style="COLOR: #0000cc">[</span>0<span style="COLOR: #0000cc">]</span><span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000cc">-</span> 1<span style="COLOR: #0000cc">;</span> i <span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">=</span> 0<span style="COLOR: #0000cc">;</span> <span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">-</span>i<span style="COLOR: #0000cc">)</span><br>&nbsp;modules<span style="COLOR: #0000cc">[</span>i<span style="COLOR: #0000cc">]</span><span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>Uninit<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span></font></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
<br>B. 老老实实的一个一个的来.</div>
<div>
<table style="BORDER-COLLAPSE: collapse" borderColor=#999999 cellSpacing=0 cellPadding=0 width="55%" bgColor=#f1f1f1 border=1>
    <tbody>
        <tr>
            <td>
            <p style="MARGIN: 5px; LINE-HEIGHT: 150%"><code><span style="COLOR: #000000"><font face=NSimsun><span style="COLOR: #ff9900">// 初始化时:<br></span>Module1<span style="COLOR: #0000cc">.</span>Init<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>Module2<span style="COLOR: #0000cc">.</span>Init<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>Module3<span style="COLOR: #0000cc">.</span>Init<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><br></font><font face=NSimsun><span style="COLOR: #ff9900">// 退出时:<br></span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><br>Module3<span style="COLOR: #0000cc">.</span>Uninit<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>Module2<span style="COLOR: #0000cc">.</span>Uninit<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>Module1<span style="COLOR: #0000cc">.</span>Uninit<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span></font></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<div>如果你读了我的上一篇, 你肯定能猜到我的选择是B. 但我想先说说A, 把A说清楚了, 选择B的理由也就出来了.</div>
<p>A是典型的数据驱动 + Builder模式, 它最大的优点是增加或删除一个模块只需要增加或删除一个数据项, 耦合很小, 所以看起来非常优雅.</p>
<p>而A的缺点有两个. 和上一篇一样, 其中之一也出在调试上: 当一个模块初始化失败后, 如果我们只看外面这些代码, 没有办法一眼得出是谁失败了, 必须得多一些操作才行.</p>
<p>第二点是A实现强制了模块的初始化和退出顺序, 先初始化的模块后退出貌似很合理, 但在一个大型系统中却总会出例外, 而且还可能出现Module1先初始化一半, 然后Module2初始化, 之后Module1再继续初始化等情况. 当然, 我们可以使用"把初始化顺序和退出顺序定义在两个数组中"或"把初始化划分为多个阶段"等方法处理这些问题, 但这些方法都会增加复杂性, 而且也都不能从根本上解决问题.</p>
<p>B实现则用简单直接的方法很好的避免了A的问题, 虽然它看起来好像很笨, 增加删除一个模块要改多个地方, 但这些改动总共也不过几行代码, 而且往往只涉及一个文件, 所以总体代价并不高.</p>
<p>最后, 本文的场景乍看起来非常适合使用Builder模式, 可为什么使用它的效果不好呢? 我本人对设计模式不感冒也不擅长, 所以只能试着解释一下这个问题: 其原因就是这个场景只是看起来像, 但其实并不适用Builder模式. Builder模式要求对象支持统一的接口, 也希望对象之间没什么关联, 这是我们作设计时追求的目标, 但在实现一个复杂系统时却很难完全满足这些要求, 所以硬套上去就会出问题. 而且在实现一个系统时, 各个模块还不可能完全定下来, 实现过程中的改动也会给Buidler模式带来麻烦. 按我个人的理解, Buidler模式不应被用来处理系统的主体模块, 它真正的适用场合之一是实现对插件的支持, 把所有插件定义在一个列表中, 然后逐项处理, 因为这时系统的主体功能已经完成, 所以可以为插件定义出清晰的接口, 而且就算定义的接口有一点问题, 它所影响的也只是某些插件而非主体功能了.</p>
<br><br><br>
<div></div>
<img src ="http://www.cppblog.com/localvar/aggbug/136645.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2010-12-16 16:24 <a href="http://www.cppblog.com/localvar/archive/2010/12/16/136645.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编写可维护的代码(一)</title><link>http://www.cppblog.com/localvar/archive/2010/10/29/132764.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Fri, 29 Oct 2010 05:24:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2010/10/29/132764.html</guid><description><![CDATA[<p>可维护性我认为主要由两个方面构成, 一是可读性, 也就是代码要能让人看懂; 二是可调试性, 出了问题可以很快的找到原因. 市面上讲设计的书很多, 但大部分侧重于灵活性和可复用性, 比如面向对象设计和设计模式等. 灵活和可复用并没有什么错, 但我认为可维护要更重要一些, 试想如果一个模块非常灵活并被大量复用, 却不可维护, 岂不是不出问题则已, 一出就是灾难性的吗?<br><br>再看C++语言, C++是一个提供了太多特性的语言, 每一件事情都可以用好几种可选的特性去实现, 但我们应该选择哪一种呢? 显然应该是最合适, 最实用的, 而不是最新最酷的.<br><br>从05年末到09年初, 我得到了一个非常难得的机会: 把一个项目做了两遍. 第一遍的时候用了很多C++的高级特性, 也有意无意的引入了一个设计模式的思想, 项目也还成功, 但后续的维护却越来越难. 后来在做第二遍的时候, 受《UNIX编程艺术》等的影响(也就是在这时候我成了把C++当C用的程序员), 开始学习用最简单直接的方法解决问题. 而结果也相当好, 不光项目成功, 整个系统的可维护性也不错. 而且虽然设计时完全没考虑面向对象, 设计模式, 但最终的系统却又带着这些东西的影子, 只是实现方法和书上写的不完全一样. (呵呵, 吹大了 欢迎大家对这一段扔几个西红柿鸡蛋之类的).<br><br>现在由于工作变动开始维护另一个系统, 这是一个很C++, 很面向对象, 也很设计模式的系统, 可是维护起来却无比困难, 出问题后简直无从下手. 所以更体会到了可维护性的重要, 进而想到应该把自己的这点经验总结一下, 写出来. 目前总共有四五篇的题材, 都是很细节的问题,&nbsp; 希望自己能坚持写完. 我的方法也许不那么漂亮, 但应该还实用, 毕竟也算是真刀真枪的实战中总结出来的.<br><br>因为一发出来就被批了个体无完肤, 所以加上了这些文字, 说明一下背景. 不太喜欢口水仗, 后续的批评我将不再回复, 因为软件开发是工程而不是艺术, 工程讲究实用, 没有绝对的对和错, 一切都应该根据实际情况具体问题具体分析. 我写的东西只是供大家参考, 没有也无法强迫大家一定要用.<br><br>下面开始正题. 如果我们要实现一个类, 用于从流式缓冲区读出数据(典型应用是网络通讯中的数据包分析), 你会用下面哪种实现呢(错误处理用的是异常, 与主题关系不大, 故不详述)?</p>
<div>
<table style="BORDER-COLLAPSE: collapse" borderColor=#999999 cellSpacing=0 cellPadding=0 width="60%" bgColor=#f1f1f1 border=1>
    <tbody>
        <tr>
            <td>
            <p style="MARGIN: 5px; LINE-HEIGHT: 150%"><code><span style="COLOR: #000000"><font face=NSimsun><span style="COLOR: #ff9900">// A实现<br></span><span style="COLOR: #0000ff">class</span> CBufferReaderA<br><span style="COLOR: #0000cc">{</span><br>&nbsp;<span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><br>&nbsp;<span style="COLOR: #0000ff">template</span><span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #0000ff">class</span> T<span style="COLOR: #0000cc">&gt;</span><br>&nbsp;CBufferReaderA<span style="COLOR: #0000cc">&amp;</span> <span style="COLOR: #0000ff">operator</span><span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">(</span> T<span style="COLOR: #0000cc">&amp;</span> v <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;<span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><br><span style="COLOR: #0000cc">}</span><span style="COLOR: #0000cc">;</span><br><br></font><font face=NSimsun><span style="COLOR: #ff9900">// B实现<br></span><span style="COLOR: #0000ff">class</span> CBufferReaderB<br><span style="COLOR: #0000cc">{</span><br>&nbsp;<span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><br>&nbsp;<span style="COLOR: #0000ff">char</span> ReadChar<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;<span style="COLOR: #0000ff">short</span> ReadShort<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;<span style="COLOR: #0000ff">int</span> ReadInt<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;<span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><br><span style="COLOR: #0000cc">}</span><span style="COLOR: #0000cc">;</span></font></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<div>我想不少人会选择A, 因为看起来更酷一些, 而且只写了一个模板函数就可以处理一大堆数据类型了, 但实际上, 如果从可维护性和实用性来说, B却更好一点. 下面就来对比分析一下.<br><br></div>
<p>1. 像cin/cout一样, A实现能把多个操作写在一起.</p>
<div>
<table style="BORDER-COLLAPSE: collapse" borderColor=#999999 cellSpacing=0 cellPadding=0 width="60%" bgColor=#f1f1f1 border=1>
    <tbody>
        <tr>
            <td>
            <p style="MARGIN: 5px; LINE-HEIGHT: 150%"><code><span style="COLOR: #000000"><font face=NSimsun>CBufferReaderA br<span style="COLOR: #0000cc">;</span><br>br <span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">&gt;</span> a <span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">&gt;</span> b <span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">&gt;</span> c <span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">&gt;</span> d<span style="COLOR: #0000cc">;</span></font></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<div>这一点B是作不到的, 因为它的返回值被用来返回实际读取的内容了. 可是当我们调试A实现支持的那一串代码时, 问题就出现了, 整个代码虽然是好几个函数调用, 但一下就执行过去了, 根本没法看到中间结果(VC是这样, 其他调试器不清楚). 为了避免这个问题, 只好把这一串操作拆成单个的, 但这样一来A和B也就没什么区别了.<br><br></div>
<p>2. 如果需要跳过一段数据, 需要怎么做呢? 如果用A实现, 肯定是类似下面的方法:<br></p>
<div>
<table style="BORDER-COLLAPSE: collapse" borderColor=#999999 cellSpacing=0 cellPadding=0 width="60%" bgColor=#f1f1f1 border=1>
    <tbody>
        <tr>
            <td>
            <p style="MARGIN: 5px; LINE-HEIGHT: 150%"><code><span style="COLOR: #000000"><font face=NSimsun><span style="COLOR: #0000ff">int</span> tmp<span style="COLOR: #0000cc">;</span><br>br <span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">&gt;</span> tmp<span style="COLOR: #0000cc">;</span></font></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<div>而B实现则可以直接:<br></div>
<div>
<table style="BORDER-COLLAPSE: collapse" borderColor=#999999 cellSpacing=0 cellPadding=0 width="60%" bgColor=#f1f1f1 border=1>
    <tbody>
        <tr>
            <td>
            <p style="MARGIN: 5px; LINE-HEIGHT: 150%"><code><span style="COLOR: #000000"><font face=NSimsun>br<span style="COLOR: #0000cc">.</span>ReadInt<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span></font></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<div>对比可见, A实现不光多用了一个没有什么实际用处的变量, 而且多写了一行代码. 只看这一点也许没多大问题, 但如果程序很大, 类似需求很多, 它带来的混乱就不可忽视了.<br><br></div>
<div>&nbsp;3. 缓冲区中是char型, 但我想用int保存读出的数据, 应该怎么办?<br>A实现:<br>
<table style="BORDER-COLLAPSE: collapse" borderColor=#999999 cellSpacing=0 cellPadding=0 width="60%" bgColor=#f1f1f1 border=1>
    <tbody>
        <tr>
            <td>
            <p style="MARGIN: 5px; LINE-HEIGHT: 150%"><code><span style="COLOR: #000000"><font face=NSimsun>char c<span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000ff">int</span> i<span style="COLOR: #0000cc">;</span><br>br <span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">&gt;</span> c<span style="COLOR: #0000cc">;</span><br>i <span style="COLOR: #0000cc">=</span> c</font></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
B实现:<br>
<table style="BORDER-COLLAPSE: collapse" borderColor=#999999 cellSpacing=0 cellPadding=0 width="60%" bgColor=#f1f1f1 border=1>
    <tbody>
        <tr>
            <td>
            <p style="MARGIN: 5px; LINE-HEIGHT: 150%"><code><span style="COLOR: #000000"><font face=NSimsun><span style="COLOR: #0000ff">int</span> i <span style="COLOR: #0000cc">=</span> br<span style="COLOR: #0000cc">.</span>ReadChar<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span></font></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
我想B的优势不用我说了吧.<br><br></div>
<div>&nbsp;4. 前面说到的A缺点也许还不算太严重, 下面这个应该就有足够的说服力了.<br>A实现:<br>
<table style="BORDER-COLLAPSE: collapse" borderColor=#999999 cellSpacing=0 cellPadding=0 width="60%" bgColor=#f1f1f1 border=1>
    <tbody>
        <tr>
            <td>
            <p style="MARGIN: 5px; LINE-HEIGHT: 150%"><code><span style="COLOR: #000000"><font face=NSimsun>br <span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">&gt;</span> a<span style="COLOR: #0000cc">;</span><br>br <span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">&gt;</span> b<span style="COLOR: #0000cc">;</span><br>br <span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">&gt;</span> c<span style="COLOR: #0000cc">;</span><br>br <span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">&gt;</span> d<span style="COLOR: #0000cc">;</span><br>br <span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">&gt;</span> e<span style="COLOR: #0000cc">;</span></font></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
B实现:<br>
<table style="BORDER-COLLAPSE: collapse" borderColor=#999999 cellSpacing=0 cellPadding=0 width="60%" bgColor=#f1f1f1 border=1>
    <tbody>
        <tr>
            <td>
            <p style="MARGIN: 5px; LINE-HEIGHT: 150%"><code><span style="COLOR: #000000"><font face=NSimsun>a <span style="COLOR: #0000cc">=</span> br<span style="COLOR: #0000cc">.</span>ReadChar<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>b <span style="COLOR: #0000cc">=</span> br<span style="COLOR: #0000cc">.</span>ReadShort<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>c <span style="COLOR: #0000cc">=</span> br<span style="COLOR: #0000cc">.</span>ReadChar<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>d <span style="COLOR: #0000cc">=</span> br<span style="COLOR: #0000cc">.</span>ReadInt<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>e <span style="COLOR: #0000cc">=</span> br<span style="COLOR: #0000cc">.</span>ReadInt<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span></font></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
看出问题了吗? 没错, 在B实现中, 我们很容易的知道每步操作从缓冲区中读了多少数据. 而如果用A实现, 这些信息就不那么明显, 必须去检查各个变量的定义, 也许你会说VC里面把鼠标放上去就能看到定义, 但也别忘了一次只能看一个, 而B则可统观全局. 如果是个很大的程序, 那B的可读性和可调试性要高很多.<br><br></div>
<div>&nbsp;5. 对B的一个批评是暴露了实现细节, 把读了几个字节清晰的写出来了. 但我认为这恰恰是它的优点, 因为只有应该隐藏的细节才需要隐藏, 而这里, 知道读几个字节对缓冲区分析来说非常重要的, 是不应该被隐藏掉的. 无限制的隐藏细节只会给自己找麻烦. 打个比方, 把路的细节隐藏起来, 方法之一是把眼睛蒙上, 我们又怎么走路呢?<br><br></div>
<div>&nbsp;6. B相对于A也有一个缺点, 就是A可以通过重定义&gt;&gt;运算符, 让自定义类型和原生类型使用看起来完全相同的方法被读出来, 但一般来说, 这一点的艺术性远大于实用性, 而且考虑到前面所有的缺点, 它不足以成为我们选择A的理由.</div>
<img src ="http://www.cppblog.com/localvar/aggbug/132764.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2010-10-29 13:24 <a href="http://www.cppblog.com/localvar/archive/2010/10/29/132764.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个支持多线程的内存池</title><link>http://www.cppblog.com/localvar/archive/2010/10/28/132765.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Thu, 28 Oct 2010 09:45:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2010/10/28/132765.html</guid><description><![CDATA[<p>代码并不复杂，不多做解释了，用的是windows api，但应该不难移植。<br><br>头文件:</p>
<table style="BORDER-COLLAPSE: collapse" border=1 cellSpacing=0 borderColor=#999999 cellPadding=0 width="75%" bgColor=#f1f1f1>
    <tbody>
        <tr>
            <td>
            <p style="LINE-HEIGHT: 150%; MARGIN: 5px"><code><span style="COLOR: #000000"><span style="COLOR: #0000cc">#</span><span style="COLOR: #ff0000">pragma</span> once<br><br><span style="COLOR: #0000ff">int</span> mp_register_usage<span style="COLOR: #0000cc">(</span> <span style="COLOR: #ff0000">size_t</span> size<span style="COLOR: #0000cc">,</span> <span style="COLOR: #ff0000">size_t</span> <span style="COLOR: #ff0000">count</span> <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000ff">bool</span> mp_create<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000ff">void</span> mp_destory<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000ff">void</span><span style="COLOR: #0000cc">*</span> mp_alloc<span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000ff">int</span> objtype <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000ff">void</span> mp_free<span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000ff">int</span> objtype<span style="COLOR: #0000cc">,</span> <span style="COLOR: #0000ff">void</span><span style="COLOR: #0000cc">*</span> mem <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
<p><br>实现文件：</p>
<p>&nbsp;</p>
<table style="BORDER-COLLAPSE: collapse" border=1 cellSpacing=0 borderColor=#999999 cellPadding=0 width="75%" bgColor=#f1f1f1>
    <tbody>
        <tr>
            <td>
            <p style="LINE-HEIGHT: 150%; MARGIN: 5px"><code><span style="COLOR: #000000"><span style="COLOR: #0000cc">#</span><span style="COLOR: #ff0000">include</span> <span style="COLOR: #0000cc">&lt;</span>windows<span style="COLOR: #0000cc">.</span>h<span style="COLOR: #0000cc">&gt;</span><br><br><span style="COLOR: #ff9900">////////////////////////////////////////////////////////////////////////////////<br></span><br><span style="COLOR: #0000cc">#</span><span style="COLOR: #ff0000">define</span> MP_MAX_OBJECT_TYPE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;8<br><br><span style="COLOR: #0000ff">struct</span> MP_OBJECT_ENTRY<br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;SLIST_HEADER lsthdr<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff0000">size_t</span> size<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff0000">size_t</span> <span style="COLOR: #ff0000">count</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">}</span><span style="COLOR: #0000cc">;</span><br><br><span style="COLOR: #0000ff">static</span> MP_OBJECT_ENTRY s_entries<span style="COLOR: #0000cc">[</span>MP_MAX_OBJECT_TYPE<span style="COLOR: #0000cc">]</span> <span style="COLOR: #0000cc">=</span> <span style="COLOR: #0000cc">{</span> 0 <span style="COLOR: #0000cc">}</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000ff">static</span> <span style="COLOR: #0000ff">void</span><span style="COLOR: #0000cc">*</span> s_base <span style="COLOR: #0000cc">=</span> <span style="COLOR: #ff0000">NULL</span><span style="COLOR: #0000cc">;</span><br><br><span style="COLOR: #ff9900">////////////////////////////////////////////////////////////////////////////////<br></span><br><span style="COLOR: #0000ff">int</span> mp_register_usage<span style="COLOR: #0000cc">(</span> <span style="COLOR: #ff0000">size_t</span> size<span style="COLOR: #0000cc">,</span> <span style="COLOR: #ff0000">size_t</span> <span style="COLOR: #ff0000">count</span> <span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">if</span><span style="COLOR: #0000cc">(</span> size <span style="COLOR: #0000cc">=</span><span style="COLOR: #0000cc">=</span> 0 <span style="COLOR: #0000cc">|</span><span style="COLOR: #0000cc">|</span> <span style="COLOR: #ff0000">count</span> <span style="COLOR: #0000cc">=</span><span style="COLOR: #0000cc">=</span> 0 <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">return</span> <span style="COLOR: #0000cc">-</span>1<span style="COLOR: #0000cc">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;size <span style="COLOR: #0000cc">+</span><span style="COLOR: #0000cc">=</span> MEMORY_ALLOCATION_ALIGNMENT <span style="COLOR: #0000cc">-</span> 1<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;size <span style="COLOR: #0000cc">/</span><span style="COLOR: #0000cc">=</span> MEMORY_ALLOCATION_ALIGNMENT<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;size <span style="COLOR: #0000cc">*</span><span style="COLOR: #0000cc">=</span> MEMORY_ALLOCATION_ALIGNMENT<span style="COLOR: #0000cc">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">for</span><span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000ff">int</span> i <span style="COLOR: #0000cc">=</span> 0<span style="COLOR: #0000cc">;</span> i <span style="COLOR: #0000cc">&lt;</span> MP_MAX_OBJECT_TYPE<span style="COLOR: #0000cc">;</span> <span style="COLOR: #0000cc">+</span><span style="COLOR: #0000cc">+</span>i <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MP_OBJECT_ENTRY<span style="COLOR: #0000cc">*</span> entry <span style="COLOR: #0000cc">=</span> s_entries <span style="COLOR: #0000cc">+</span> i<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">if</span><span style="COLOR: #0000cc">(</span> entry<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>size <span style="COLOR: #0000cc">=</span><span style="COLOR: #0000cc">=</span> size <span style="COLOR: #0000cc">|</span><span style="COLOR: #0000cc">|</span> entry<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>size <span style="COLOR: #0000cc">=</span><span style="COLOR: #0000cc">=</span> 0 <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entry<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>size <span style="COLOR: #0000cc">=</span> size<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entry<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #ff0000">count</span> <span style="COLOR: #0000cc">+</span><span style="COLOR: #0000cc">=</span> <span style="COLOR: #ff0000">count</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">return</span> i<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">return</span> <span style="COLOR: #0000cc">-</span>1<span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #ff9900">//------------------------------------------------------------------------------<br></span><br><span style="COLOR: #0000ff">bool</span> mp_create<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff0000">size_t</span> total <span style="COLOR: #0000cc">=</span> 0<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">for</span><span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000ff">int</span> i <span style="COLOR: #0000cc">=</span> 0<span style="COLOR: #0000cc">;</span> i <span style="COLOR: #0000cc">&lt;</span> MP_MAX_OBJECT_TYPE<span style="COLOR: #0000cc">;</span> <span style="COLOR: #0000cc">+</span><span style="COLOR: #0000cc">+</span>i <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;total <span style="COLOR: #0000cc">+</span><span style="COLOR: #0000cc">=</span> s_entries<span style="COLOR: #0000cc">[</span>i<span style="COLOR: #0000cc">]</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #ff0000">count</span> <span style="COLOR: #0000cc">*</span> s_entries<span style="COLOR: #0000cc">[</span>i<span style="COLOR: #0000cc">]</span><span style="COLOR: #0000cc">.</span>size<span style="COLOR: #0000cc">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;s_base <span style="COLOR: #0000cc">=</span> VirtualAlloc<span style="COLOR: #0000cc">(</span> <span style="COLOR: #ff0000">NULL</span><span style="COLOR: #0000cc">,</span> total<span style="COLOR: #0000cc">,</span> MEM_COMMIT<span style="COLOR: #0000cc">,</span> PAGE_READWRITE <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">if</span><span style="COLOR: #0000cc">(</span> s_base <span style="COLOR: #0000cc">=</span><span style="COLOR: #0000cc">=</span> <span style="COLOR: #ff0000">NULL</span> <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">return</span> <span style="COLOR: #0000ff">false</span><span style="COLOR: #0000cc">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">char</span><span style="COLOR: #0000cc">*</span> base <span style="COLOR: #0000cc">=</span> <span style="COLOR: #0000ff">reinterpret_cast</span><span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #0000cc">*</span><span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">(</span> s_base <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">for</span><span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000ff">int</span> i <span style="COLOR: #0000cc">=</span> 0<span style="COLOR: #0000cc">;</span> i <span style="COLOR: #0000cc">&lt;</span> MP_MAX_OBJECT_TYPE<span style="COLOR: #0000cc">;</span> <span style="COLOR: #0000cc">+</span><span style="COLOR: #0000cc">+</span>i <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MP_OBJECT_ENTRY<span style="COLOR: #0000cc">*</span> entry <span style="COLOR: #0000cc">=</span> s_entries <span style="COLOR: #0000cc">+</span> i<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InitializeSListHead<span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000cc">&amp;</span>entry<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>lsthdr <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">char</span><span style="COLOR: #0000cc">*</span> addr <span style="COLOR: #0000cc">=</span> base <span style="COLOR: #0000cc">+</span> entry<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>size <span style="COLOR: #0000cc">*</span> entry<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #ff0000">count</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addr <span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">=</span> MEMORY_ALLOCATION_ALIGNMENT<span style="COLOR: #0000cc">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">for</span><span style="COLOR: #0000cc">(</span> <span style="COLOR: #ff0000">size_t</span> j <span style="COLOR: #0000cc">=</span> 0<span style="COLOR: #0000cc">;</span> j <span style="COLOR: #0000cc">&lt;</span> entry<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #ff0000">count</span><span style="COLOR: #0000cc">;</span> <span style="COLOR: #0000cc">+</span><span style="COLOR: #0000cc">+</span>j <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SLIST_ENTRY<span style="COLOR: #0000cc">*</span> node <span style="COLOR: #0000cc">=</span> <span style="COLOR: #0000ff">reinterpret_cast</span><span style="COLOR: #0000cc">&lt;</span>SLIST_ENTRY<span style="COLOR: #0000cc">*</span><span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">(</span> addr <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InterlockedPushEntrySList<span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000cc">&amp;</span>entry<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>lsthdr<span style="COLOR: #0000cc">,</span> node <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addr <span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">=</span> entry<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>size<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;base <span style="COLOR: #0000cc">+</span><span style="COLOR: #0000cc">=</span> entry<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #ff0000">count</span> <span style="COLOR: #0000cc">*</span> entry<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>size<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">return</span> <span style="COLOR: #0000ff">true</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #ff9900">//------------------------------------------------------------------------------<br></span><br><span style="COLOR: #0000ff">void</span> mp_destory<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">if</span><span style="COLOR: #0000cc">(</span> s_base <span style="COLOR: #0000cc">!</span><span style="COLOR: #0000cc">=</span> <span style="COLOR: #ff0000">NULL</span> <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;VirtualFree<span style="COLOR: #0000cc">(</span> s_base<span style="COLOR: #0000cc">,</span> 0<span style="COLOR: #0000cc">,</span> MEM_RELEASE <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s_base <span style="COLOR: #0000cc">=</span> <span style="COLOR: #ff0000">NULL</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br><span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #ff9900">//------------------------------------------------------------------------------<br></span><br><span style="COLOR: #0000ff">void</span><span style="COLOR: #0000cc">*</span> mp_alloc<span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000ff">int</span> objtype <span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;MP_OBJECT_ENTRY<span style="COLOR: #0000cc">*</span> entry <span style="COLOR: #0000cc">=</span> s_entries <span style="COLOR: #0000cc">+</span> objtype<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;SLIST_ENTRY<span style="COLOR: #0000cc">*</span> node <span style="COLOR: #0000cc">=</span> InterlockedPopEntrySList<span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000cc">&amp;</span>entry<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>lsthdr <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">char</span><span style="COLOR: #0000cc">*</span> p <span style="COLOR: #0000cc">=</span> <span style="COLOR: #0000ff">reinterpret_cast</span><span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #0000cc">*</span><span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">(</span> node <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">if</span><span style="COLOR: #0000cc">(</span> p <span style="COLOR: #0000cc">!</span><span style="COLOR: #0000cc">=</span> <span style="COLOR: #ff0000">NULL</span> <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p <span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">=</span> entry<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>size <span style="COLOR: #0000cc">-</span> MEMORY_ALLOCATION_ALIGNMENT<span style="COLOR: #0000cc">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">return</span> p<span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #ff9900">//------------------------------------------------------------------------------<br></span><br><span style="COLOR: #0000ff">void</span> mp_free<span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000ff">int</span> objtype<span style="COLOR: #0000cc">,</span> <span style="COLOR: #0000ff">void</span><span style="COLOR: #0000cc">*</span> mem <span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">if</span><span style="COLOR: #0000cc">(</span> mem <span style="COLOR: #0000cc">=</span><span style="COLOR: #0000cc">=</span> <span style="COLOR: #ff0000">NULL</span> <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">return</span><span style="COLOR: #0000cc">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;MP_OBJECT_ENTRY<span style="COLOR: #0000cc">*</span> entry <span style="COLOR: #0000cc">=</span> s_entries <span style="COLOR: #0000cc">+</span> objtype<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">char</span><span style="COLOR: #0000cc">*</span> p <span style="COLOR: #0000cc">=</span> <span style="COLOR: #0000ff">reinterpret_cast</span><span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #0000cc">*</span><span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">(</span> mem <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;p <span style="COLOR: #0000cc">+</span><span style="COLOR: #0000cc">=</span> entry<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>size <span style="COLOR: #0000cc">-</span> MEMORY_ALLOCATION_ALIGNMENT<span style="COLOR: #0000cc">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;SLIST_ENTRY<span style="COLOR: #0000cc">*</span> node <span style="COLOR: #0000cc">=</span> <span style="COLOR: #0000ff">reinterpret_cast</span><span style="COLOR: #0000cc">&lt;</span>SLIST_ENTRY<span style="COLOR: #0000cc">*</span><span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">(</span> p <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;InterlockedPushEntrySList<span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000cc">&amp;</span>s_entries<span style="COLOR: #0000cc">[</span>objtype<span style="COLOR: #0000cc">]</span><span style="COLOR: #0000cc">.</span>lsthdr<span style="COLOR: #0000cc">,</span> node <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #ff9900">////////////////////////////////////////////////////////////////////////////////<br></span><br></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
<p><br>应用举例：</p>
<table style="BORDER-COLLAPSE: collapse" border=1 cellSpacing=0 borderColor=#999999 cellPadding=0 width="75%" bgColor=#f1f1f1>
    <tbody>
        <tr>
            <td>
            <p style="LINE-HEIGHT: 150%; MARGIN: 5px"><code><span style="COLOR: #000000"><span style="COLOR: #ff9900">////////////////////////////////////////////////////////////////////////////////<br></span><br><span style="COLOR: #0000ff">template</span><span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #ff0000">size_t</span> size<span style="COLOR: #0000cc">&gt;</span><br><span style="COLOR: #0000ff">class</span> CSomeObject<br><span style="COLOR: #0000cc">{</span><br><span style="COLOR: #0000ff">private</span><span style="COLOR: #0000cc">:</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">static</span> <span style="COLOR: #0000ff">int</span> s_objtype<span style="COLOR: #0000cc">;</span><br><br><span style="COLOR: #0000ff">private</span><span style="COLOR: #0000cc">:</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">char</span> m_data<span style="COLOR: #0000cc">[</span>size<span style="COLOR: #0000cc">]</span><span style="COLOR: #0000cc">;</span><br><br><span style="COLOR: #0000ff">public</span><span style="COLOR: #0000cc">:</span><br>&nbsp;&nbsp;&nbsp;&nbsp;CSomeObject<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000cc">{</span><span style="COLOR: #0000cc">}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">void</span> DoSomeThing<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_tprintf<span style="COLOR: #0000cc">(</span> _T<span style="COLOR: #0000cc">(</span><span style="COLOR: #ff00ff">"Object Type = %d, Object Size = %d\n"</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">,</span> s_objtype<span style="COLOR: #0000cc">,</span> size <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">~</span>CSomeObject<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000cc">{</span><span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #0000ff">public</span><span style="COLOR: #0000cc">:</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">static</span> <span style="COLOR: #0000ff">void</span> RegisterMemoryUsage<span style="COLOR: #0000cc">(</span> <span style="COLOR: #ff0000">size_t</span> <span style="COLOR: #ff0000">count</span> <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s_objtype <span style="COLOR: #0000cc">=</span> mp_register_usage<span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #0000cc">(</span>CSomeObject<span style="COLOR: #0000cc">&lt;</span>size<span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">,</span> <span style="COLOR: #ff0000">count</span> <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">static</span> <span style="COLOR: #0000ff">void</span><span style="COLOR: #0000cc">*</span> <span style="COLOR: #0000ff">operator</span> <span style="COLOR: #0000ff">new</span><span style="COLOR: #0000cc">(</span> <span style="COLOR: #ff0000">size_t</span> size <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">return</span> mp_alloc<span style="COLOR: #0000cc">(</span> s_objtype <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">static</span> <span style="COLOR: #0000ff">void</span> <span style="COLOR: #0000ff">operator</span> <span style="COLOR: #0000ff">delete</span><span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000ff">void</span><span style="COLOR: #0000cc">*</span> mem <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mp_free<span style="COLOR: #0000cc">(</span> s_objtype<span style="COLOR: #0000cc">,</span> mem <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br><span style="COLOR: #0000cc">}</span><span style="COLOR: #0000cc">;</span><br><br><span style="COLOR: #0000ff">template</span><span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #ff0000">size_t</span> size<span style="COLOR: #0000cc">&gt;</span> <span style="COLOR: #0000ff">int</span> CSomeObject<span style="COLOR: #0000cc">&lt;</span>size<span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">:</span>s_objtype <span style="COLOR: #0000cc">=</span> -1<span style="COLOR: #0000cc">;</span><br><br><span style="COLOR: #ff9900">////////////////////////////////////////////////////////////////////////////////<br></span><br>HANDLE g_stopevent <span style="COLOR: #0000cc">=</span> <span style="COLOR: #ff0000">NULL</span><span style="COLOR: #0000cc">;</span><br><br><span style="COLOR: #0000cc">#</span><span style="COLOR: #ff0000">define</span> TEST_OBJECT<span style="COLOR: #0000cc">(</span> c<span style="COLOR: #0000cc">,</span> s <span style="COLOR: #0000cc">)</span> \<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">case</span> c<span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">\</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><span style="COLOR: #0000cc">\</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CSomeObject<span style="COLOR: #0000cc">&lt;</span>s<span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">*</span> p <span style="COLOR: #0000cc">=</span> <span style="COLOR: #0000ff">new</span> CSomeObject<span style="COLOR: #0000cc">&lt;</span>s<span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">;</span><span style="COLOR: #0000cc">\</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">if</span><span style="COLOR: #0000cc">(</span> p <span style="COLOR: #0000cc">!</span><span style="COLOR: #0000cc">=</span> <span style="COLOR: #ff0000">NULL</span> <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">\</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><span style="COLOR: #0000cc">\</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>DoSomeThing<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><span style="COLOR: #0000cc">\</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">delete</span> p<span style="COLOR: #0000cc">;</span><span style="COLOR: #0000cc">\</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><span style="COLOR: #0000cc">\</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><span style="COLOR: #0000cc">\</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">break</span><span style="COLOR: #0000cc">;</span><br><br><span style="COLOR: #ff0000">uintptr_t</span> __stdcall worker_thread<span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000ff">void</span><span style="COLOR: #0000cc">*</span> <span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff0000">srand</span><span style="COLOR: #0000cc">(</span> GetTickCount<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">while</span><span style="COLOR: #0000cc">(</span> WaitForSingleObject<span style="COLOR: #0000cc">(</span> g_stopevent<span style="COLOR: #0000cc">,</span> 0 <span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000cc">=</span><span style="COLOR: #0000cc">=</span> WAIT_TIMEOUT <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">switch</span><span style="COLOR: #0000cc">(</span> <span style="COLOR: #ff0000">rand</span><span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000cc">%</span> 7 <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TEST_OBJECT<span style="COLOR: #0000cc">(</span> 0<span style="COLOR: #0000cc">,</span> 1 <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TEST_OBJECT<span style="COLOR: #0000cc">(</span> 1<span style="COLOR: #0000cc">,</span> 9 <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TEST_OBJECT<span style="COLOR: #0000cc">(</span> 2<span style="COLOR: #0000cc">,</span> 10 <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TEST_OBJECT<span style="COLOR: #0000cc">(</span> 3<span style="COLOR: #0000cc">,</span> 20 <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TEST_OBJECT<span style="COLOR: #0000cc">(</span> 4<span style="COLOR: #0000cc">,</span> 36 <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TEST_OBJECT<span style="COLOR: #0000cc">(</span> 5<span style="COLOR: #0000cc">,</span> 100 <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TEST_OBJECT<span style="COLOR: #0000cc">(</span> 6<span style="COLOR: #0000cc">,</span> 1000 <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">return</span> 0<span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #ff9900">////////////////////////////////////////////////////////////////////////////////<br></span><br><span style="COLOR: #0000ff">int</span> _tmain<span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000ff">int</span> argc<span style="COLOR: #0000cc">,</span> _TCHAR<span style="COLOR: #0000cc">*</span> argv<span style="COLOR: #0000cc">[</span><span style="COLOR: #0000cc">]</span> <span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;CSomeObject<span style="COLOR: #0000cc">&lt;</span>1<span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">:</span>RegisterMemoryUsage<span style="COLOR: #0000cc">(</span> 100 <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;CSomeObject<span style="COLOR: #0000cc">&lt;</span>9<span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">:</span>RegisterMemoryUsage<span style="COLOR: #0000cc">(</span> 2 <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;CSomeObject<span style="COLOR: #0000cc">&lt;</span>10<span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">:</span>RegisterMemoryUsage<span style="COLOR: #0000cc">(</span> 100 <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;CSomeObject<span style="COLOR: #0000cc">&lt;</span>20<span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">:</span>RegisterMemoryUsage<span style="COLOR: #0000cc">(</span> 200 <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;CSomeObject<span style="COLOR: #0000cc">&lt;</span>36<span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">:</span>RegisterMemoryUsage<span style="COLOR: #0000cc">(</span> 300 <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;CSomeObject<span style="COLOR: #0000cc">&lt;</span>100<span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">:</span>RegisterMemoryUsage<span style="COLOR: #0000cc">(</span> 205 <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;CSomeObject<span style="COLOR: #0000cc">&lt;</span>1000<span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">:</span>RegisterMemoryUsage<span style="COLOR: #0000cc">(</span> 128 <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;mp_create<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;g_stopevent <span style="COLOR: #0000cc">=</span> CreateEvent<span style="COLOR: #0000cc">(</span> <span style="COLOR: #ff0000">NULL</span><span style="COLOR: #0000cc">,</span> <span style="COLOR: #0000ff">TRUE</span><span style="COLOR: #0000cc">,</span> <span style="COLOR: #0000ff">FALSE</span><span style="COLOR: #0000cc">,</span> <span style="COLOR: #ff0000">NULL</span> <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">for</span><span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000ff">int</span> i <span style="COLOR: #0000cc">=</span> 0<span style="COLOR: #0000cc">;</span> i <span style="COLOR: #0000cc">&lt;</span> 10<span style="COLOR: #0000cc">;</span> <span style="COLOR: #0000cc">+</span><span style="COLOR: #0000cc">+</span>i <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff0000">uintptr_t</span> h <span style="COLOR: #0000cc">=</span> _beginthreadex<span style="COLOR: #0000cc">(</span> <span style="COLOR: #ff0000">NULL</span><span style="COLOR: #0000cc">,</span> 0<span style="COLOR: #0000cc">,</span> worker_thread<span style="COLOR: #0000cc">,</span> <span style="COLOR: #ff0000">NULL</span><span style="COLOR: #0000cc">,</span> 0<span style="COLOR: #0000cc">,</span> <span style="COLOR: #ff0000">NULL</span> <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle<span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000ff">reinterpret_cast</span><span style="COLOR: #0000cc">&lt;</span>HANDLE<span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">(</span> h <span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;_getch<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;SetEvent<span style="COLOR: #0000cc">(</span> g_stopevent <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff0000">Sleep</span><span style="COLOR: #0000cc">(</span> 500 <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle<span style="COLOR: #0000cc">(</span> g_stopevent <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;mp_destory<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">return</span> 0<span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #ff9900">////////////////////////////////////////////////////////////////////////////////<br></span><br></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
<br><img src="http://blog.vckbase.com/localvar/aggbug/51946.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132765.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2010-10-28 17:45 <a href="http://www.cppblog.com/localvar/archive/2010/10/28/132765.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>过年了，送大家个小玩具</title><link>http://www.cppblog.com/localvar/archive/2009/12/30/132766.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Wed, 30 Dec 2009 06:07:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2009/12/30/132766.html</guid><description><![CDATA[<font size=2 face="Courier New">把下面的图打印下来，按图示折好，粘起来。注意CDE三个标签的位置，图是对的，别粘错了。粘好后闭上一只眼，距离一米左右，转动自己的头，看看效果。</font><br><img border=0 src="http://www.cppblog.com/images/vckbase_com/localvar/1257/o_toy.jpg"><br>2009年就要过去了，今年只写了一片随笔，拿这个凑个数吧。祝大家新年快乐！！<img src="http://blog.vckbase.com/localvar/aggbug/40601.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132766.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2009-12-30 14:07 <a href="http://www.cppblog.com/localvar/archive/2009/12/30/132766.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解决了一个困惑很久的bug</title><link>http://www.cppblog.com/localvar/archive/2009/01/08/132767.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Thu, 08 Jan 2009 08:58:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2009/01/08/132767.html</guid><description><![CDATA[<p>让这个bug困扰了很久，前一段太忙只找了个临时解决方案而没有追究原因，今天终于把它搞清楚了。由于测试时只在多cpu系统上出现，我甚至一度怀疑它是cpu的bug<img title=大汗 alt=大汗 src="http://vckbase.com/bbs/image/emimg/010.gif"> 。</p>
<p>两个c/s结构的网络通讯程序，服务器端使用完成端口模型，客户端使用阻塞模型，双方以一种客户端发送命令，服务器端处理，然后返回应答的方式通讯。问题出在服务器端。以下是服务器端代码的大致处理逻辑：</p>
<pre><span style="COLOR: #0000ff">long</span> <span style="COLOR: #0000ff">volatile</span> g_busy = 0;
<span style="COLOR: #0000ff">void</span> iocp_thread()
{
<span style="COLOR: #0000ff">while</span>( GetQueuedCompletionStatus() )
{
<span style="COLOR: #0000ff">if</span>( InterlockedCompareExchange( &amp;g_busy, 1, 0 ) != 0 )
WSASend( "<span style="COLOR: #8b0000">服务器忙</span>" );
<span style="COLOR: #008000">// 处理命令</span>
ProcessCommand();
WSASend( "<span style="COLOR: #8b0000">应答信息</span>" );
InterlockedExchange( &amp;g_busy, 0 );
}
}</pre>
<p>其中ProcessCommand需要互斥运行（这是简化的逻辑，实际上有很多不同的命令，有些需要互斥，有些可以并行，否则就没必要用完成端口了），并且需要一定的时间才能处理完毕。为了避免多个客户端同时执行命令，导致所有的iocp线程都等在那，我把g_busy当成了一个锁，第一个线程可以成功进入，其它的都直接向客户端返回&#8220;服务器忙&#8221;。</p>
<p>程序一直都运行的很好，直到有一天把服务器程序装到了一台有双核cpu的机器上。我发现，如果让客户端连续发送命令，即收到上一条命令的应答后立即发送下一条命令，就会随机的返回&#8220;服务器忙&#8221;，而这时只有一个客户端连接上去，按照我设想的逻辑是不可能出这种情况的。检查了半天代码，没觉得有什么问题，调试吧，又遇到了另一个难题，海森堡的测不准原理起作用了，做的工作太多问题就消失了，做的太少又得不到什么有价值的信息。搞得我很是头疼。</p>
<p>今天再次看这个问题，突然想到：它肯定和线程切换相关，所以我应该记录下每次处理命令的线程的ID，这样出错时就可以看看上次成功执行命令的那个线程在干什么了。方法正确了，问题也就迎刃而解了，我发现，出问题时，上一个线程的WSASend居然还没有返回，也就是说，客户端已经收到应答并发送了下一条命令，服务器端也收到了命令并准备处理，但上一条命令的应答却还没有完全发送完成，难怪出错了！</p>
<p>总结经验教训，感觉自己一开始被两点给误导了，一是实际程序中的WSARecv/WSASend藏的比较深，没这么明显，所以没注意到。二是当时粗略检查代码觉得没问题，就把主要精力放在ProcessCommand上了，由于我把它里面一段访问sql server的代码注释掉以后，问题就不出了，所以还看了半天atl oledb的源码，最后精疲力尽，其它事情又比较多就放弃了。</p>
<img src="http://blog.vckbase.com/localvar/aggbug/36194.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132767.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2009-01-08 16:58 <a href="http://www.cppblog.com/localvar/archive/2009/01/08/132767.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>发布一个小工具：EasyDump</title><link>http://www.cppblog.com/localvar/archive/2009/01/06/132768.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Tue, 06 Jan 2009 08:33:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2009/01/06/132768.html</guid><description><![CDATA[<p>为了分析用户使用过程中出现的软件Bug，经常需要.dmp文件的帮助。一般我们会用WinDbg或adplus制作这个文件，可这两个工具都有点&#8220;太难&#8221;了，往往要费九牛二虎之力才能教会用户。而让程序在崩溃时自动转储或用Dr. Watson转储虽然使用简单，却只能做崩溃转储，对死锁之类的情况则无能为力。</p>
<p>所以我决定自己写一个小工具降低一下制作.dmp文件的难度，也就有了今天发布的这个EasyDump（轻松转储）。代码和可执行文件都放到google code（也是刚注册的，尝试一下:)）上去了，大家可以到<a title=http://code.google.com/p/easytools/ href="http://code.google.com/p/easytools/">http://code.google.com/p/easytools/</a>下载。</p>
<p>程序还没有很好的测试过，如果有bug的话，应该可以直接在项目主页上报告。另外下一步考虑增加三个功能：首先是异常过滤，因为first chance异常太多了！如果选择了生成.dmp的话，一秒钟可能就有十个甚至更多的文件，设置了异常过滤后，可以把一些不关心的异常屏蔽掉，不生成文件。其次是如果没有second chance的话，就把first chance的文件直接删掉，也有助于减少不必要的文件。第三是界面的国际化，也发布个英文版什么的。</p>
<p>2009.01.08: 自动删除first chance文件的功能已经实现.<br>2009.01.22: 异常过滤功能已经实现.</p>
<img src="http://blog.vckbase.com/localvar/aggbug/36183.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132768.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2009-01-06 16:33 <a href="http://www.cppblog.com/localvar/archive/2009/01/06/132768.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编译选项的统一管理：Property Manager</title><link>http://www.cppblog.com/localvar/archive/2008/12/31/132769.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Wed, 31 Dec 2008 03:04:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2008/12/31/132769.html</guid><description><![CDATA[<p>当一个solution中的project越来越多以后，管理编译选项，将成为一件很麻烦的事，单独对每个project进行设置不仅繁琐，而且容易出错。但实际上，visual studio已经为我们提过了统一的管理界面—Property Manager。</p>
<p>在visual studio中，每个c++ project的general属性页中，都有一项"Inherited Project Property Sheets"，我们可以在这里指定一个或多个Property Sheet（不要和GUI开发中的Property Sheet搞混了，完全两个概念）供项目继承。在被继承的属性表（父属性表）中，我们设置好默认选项，然后把project中对应的选项设置为"inherit from parent or project defaults&#8221;就可以使用父属性表中的设置了。这样，在solution层面上准备一个Property Sheet，再让其下的所有project继承，即可实现编译选项的统一管理。</p>
<p>在visual studio的view菜单中选择property manager，还可以更清楚的看到每个project继承了哪些property sheet，并且有更多的编辑功能（如创建新property sheet、清除project已经设置了的选项等）。另外，property sheet还支持多级继承，而实践上一般也是每个solution一个根Property Sheet，然后为每个Configruation（Debug版、Release版等）分别派生出一个，各个project的不同Configruation继承对应的Property Sheet。</p>
<p>最后要注意的就是：property sheet的保存文件（.vsprops），也是应该加入配置管理系统的。</p>
<img src="http://blog.vckbase.com/localvar/aggbug/36154.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132769.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2008-12-31 11:04 <a href="http://www.cppblog.com/localvar/archive/2008/12/31/132769.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++/CLI的用途</title><link>http://www.cppblog.com/localvar/archive/2008/12/29/132770.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Mon, 29 Dec 2008 07:39:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2008/12/29/132770.html</guid><description><![CDATA[<p>作为一个有着正常审美观的人，我简直无法忍受C++/CLI（以及managed c++）的丑陋。不过，近来发现，这个丑东西也还有点用，在把原生开发接口包装成托管开发接口时，比C#的互操作容易的多（互操作看了看，头大呀）。磕磕绊绊几天，终于把一个SDK开发包转换完成了。总结经验如下：</p>
<p>1. 对于clr中的引用类型，定义变量时要用个^符，如"String^ var1"、"array&lt;int&gt;^ var2"、"array&lt;String^&gt;^ strarr"等，值类型不用。一个类型是值类型还是引用类型，取决于定义时用的是value struct/class还是ref struct/class。</p>
<p>2. 定义枚举要用enum struct/class, 否则是个原生枚举，C#里不能用。可指定数值类型和flags属性，如下：<br>&nbsp;&nbsp;&nbsp; [FlagsAttribute]<br><span style="COLOR: #0000ff">&nbsp;&nbsp;&nbsp; public</span> <span style="COLOR: #0000ff">enum</span> <span style="COLOR: #0000ff">class</span> TestEnum : unsigned <span style="COLOR: #0000ff">int</span><br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flag1 = 0x00000001,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flag2 = 0x00000002,<br>&nbsp;&nbsp;&nbsp; };</p>
<p>3. 原生字符串转换为托管字符串时，用：<br><span style="COLOR: #0000ff">&nbsp;&nbsp;&nbsp; char</span>* s1 = "<span style="COLOR: #8b0000">native string1</span>";<br>&nbsp;&nbsp;&nbsp; wchar_t* s2 = L"<span style="COLOR: #8b0000">native string2</span>";<br>&nbsp;&nbsp;&nbsp; String^ str1 = gcnew String( s1 );<br>&nbsp;&nbsp;&nbsp; String^ str2 = gcnew String( s2 );<br>托管字符串转换为原生字符串时，用：<br>&nbsp;&nbsp;&nbsp; pin_ptr&lt;const wchar_t&gt; p = PtrToStringChars( str );<br>如果需要ansi字符集，可再对p进行一些常规字符集转换。</p>
<p>4. 指针、句柄等与0进行赋值比较等操作时用nullptr，而不是NULL或0，后者会导致装箱等操作，如：<br>&nbsp;&nbsp;&nbsp; HANDLE h = nullptr;<br>&nbsp;&nbsp;&nbsp; <span style="COLOR: #0000ff">if</span>( h == nullptr ){}</p>
<p>5. C#中定义函数参数时的ref关键字在C++/CLI中用%号对应，如：<br><span style="COLOR: #0000ff">&nbsp;&nbsp;&nbsp; void</span> foo( String^% refstr );<br>out关键字，需要用[System::Runtime::InteropServices::OutAttribute]声明一下。</p>
<p>6. 数组空间初始化，用()而不是[]，也就是说它是一个函数调用，如<br>&nbsp;&nbsp;&nbsp; array&lt;<span style="COLOR: #0000ff">int</span>&gt;^ arr = gcnew array&lt;<span style="COLOR: #0000ff">int</span>&gt;(100);<br>的作用是定义一个有100个元素的数组。</p>
<p>7. C++/CLI中很多地方不能用const、volatile等关键字，如果编译报错，就把它们去掉吧。</p>
<p>8. 尽量不要定义自己的DllMain，如果必须定义的话，DllMain中不要进行任何托管操作，否则极易导致死锁。可以"#pragma managed"编译指令，临时打开或关闭托管。</p>
<p>9. 暂时没有了，等想起来再补充。</p>
<img src="http://blog.vckbase.com/localvar/aggbug/36143.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132770.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2008-12-29 15:39 <a href="http://www.cppblog.com/localvar/archive/2008/12/29/132770.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>命令行下进行数字签名</title><link>http://www.cppblog.com/localvar/archive/2008/11/18/132771.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Tue, 18 Nov 2008 03:26:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2008/11/18/132771.html</guid><description><![CDATA[<p>网上介绍数字签名的文章，大多使用signtool的signwizard命令实现，这种方式虽说简单，却需要人为干预，不能自动执行。msdn上说signtool的sign命令可以在命令行中完成签名，但描述的相当模糊，试了半天，终于找到了它的使用方法，一共执行四条命令即可，前三条一次性执行，最后生成一个个人证书(pfx)，最后一条用于实际签名，可以放在post build event中去自动执行。</p>
<p>1. makecert生成x.509证书和私钥, 会弹出界面要求输入两次密码, 我输的是123, 其中localvar studio是公司名<br>makecert /sv sign.pvk /n "CN=localvar studio" sign.cer</p>
<p>2. 把x.509证书转换为Software Publisher Certificate<br>cert2spc sign.cer sign.spc</p>
<p>3. 把pvk转换为pfx, 例子中的123是私钥密码<br>pvk2pfx -pvk sign.pvk -pi 123 -spc sign.spc -pfx sign.pfx</p>
<p>4. 签名, 稍微调整一下，就能写在post build event里了，123是密码<br>signtool sign /f sign.pfx /p 123 test.exe</p>
<p>上面的例子只是演示签名过程，由于证书是本机做出来的，所以签了名也没用，用户那看到的仍然是&#8220;未知发行商&#8221;。向证书颁发机构申请真正的证书时，能直接得到.spc和.pvk文件，所以就不用执行前两步了。</p>
<p>PS: 证书颁发机构真是坐地收钱呀，几秒钟生成个证书，每年就收好几千。</p>
<img src="http://blog.vckbase.com/localvar/aggbug/35679.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132771.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2008-11-18 11:26 <a href="http://www.cppblog.com/localvar/archive/2008/11/18/132771.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>_tfopen指定文件编码后程序崩溃</title><link>http://www.cppblog.com/localvar/archive/2008/11/03/132772.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Mon, 03 Nov 2008 04:58:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2008/11/03/132772.html</guid><description><![CDATA[vs05和08的crt增加了一点功能, 使用fopen(_wfopen)时可以指定文件的编码, 但我发现这个功能好像有很多bug, 会导致程序崩溃。<br>我是使用下面的形式打开文件的:<br>TCHAR buf[1024];<br>FILE* fp = _tfopen( _T(&#8220;a.txt&#8221;) , _T(&#8221;rt,ccs=UNICODE&#8221;) );<br>_fgetts( buf, _countof(buf), fp );<br>按msdn的说法，这时fopen会根据文件的bom自动判断文件的编码, 并保证buf中字符的编码总是我希望的那一种。<br>可是这个程序在使用mbcs并打开unicode编码的文件时会崩溃, 考虑到我的程序只发布unicode版本, 所以忍了，啥也不说。<br>但这两天发现, UNICODE版本在fgets时也会崩溃, 方法是新建一个excel文件然后重命名为a.txt。<br><br>我仔细读了两天msdn，并测试了各种形式，感觉不像是我的错误。<br>在网上没找到类似的描述, 所以记下来，也许有人会碰到同样的问题。<img src="http://blog.vckbase.com/localvar/aggbug/35543.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132772.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2008-11-03 12:58 <a href="http://www.cppblog.com/localvar/archive/2008/11/03/132772.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用SVN实现版本号自增</title><link>http://www.cppblog.com/localvar/archive/2008/05/20/132755.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Tue, 20 May 2008 01:12:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2008/05/20/132755.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;在《介绍一下SVN》一文中，我提到了自动递增版本号的功能，现在就来具体说明一下实现方法。虽然标题中说的是&#8220;使用SVN&#8221;，但我们实际用的是SVN的客户端工具TortoiseSVN中的SubWCRev程序。另外文中的例子也使用了Visual Studio的SVN插件VisualSVN，它并非必须，用了方便一些，不用也行。我平时主要使用C/C++语言，但考虑C#有更大的用户群，我的示例项目也采用了C#。
<h3></h3>
<h4>1.&nbsp;生成一个名为autover的项目</h4>
<p>&nbsp;&nbsp;&nbsp;&nbsp;注意项目的Properties文件夹下有一个名为AssemblyInfo.cs的文件，autover程序的版本号就写在它里面。</p>
<img src="http://www.cppblog.com/images/vckbase_com/localvar/1234/o_image001.jpg">
<h4>2.&nbsp;创建模板文件</h4>
<p>在windows的资源管理器中进入Properties文件夹，把AssemblyInfo.cs文件复制一份，命名为AssemblyInfo.template.cs，并把它加入到项目中来。</p>
<img src="http://www.cppblog.com/images/vckbase_com/localvar/1234/o_image002.jpg">
<h4>3.&nbsp;修改AssemblyInfo.template.cs的属性</h4>
<p>&nbsp;&nbsp;&nbsp;&nbsp;AssemblyInfo.template.cs文件是用来自动生成版本号的模板文件，它不应该被编译，所以我们要把它的Build Action改成None，如下图所示：</p>
<img src="http://www.cppblog.com/images/vckbase_com/localvar/1234/o_image003.jpg">
<h4>4.&nbsp;修改AssemblyInfo.template.cs的内容</h4>
<p>&nbsp;&nbsp;&nbsp;&nbsp;在这个文件中，你能找到如下两行代码： <br><font color=#0000ff>[assembly: AssemblyVersion( "1.0.0.0" )] <br>[assembly: AssemblyFileVersion( "1.0.0.0" )] <br></font>其中的&#8220;1.0.0.0&#8221;就是程序的版本号，它使用的是&#8220;主版本号.次版本号.内部版本号.修订号&#8221;的形式。前三个改成你自己需要的数字，最后一个改成&#8220;$WCREV$&#8221;，改完之后应该是类似下面的样子： <br><font color=#0000ff>[assembly: AssemblyVersion( "1.0.0.$WCREV$" )] <br>[assembly: AssemblyFileVersion( "1.0.0.$WCREV$" )]</font></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;在这个文件的最后，你还应该加上下面两段代码，它们可以检测出有本地修改（修改了但没有提交）的代码和有混合版本的代码。 <br><font color=#0000ff>#if $WCMIXED?true:false$ <br>#if DEBUG <br>#warning mixed update revisions founded <br>#else <br>#error mixed update revisions founded <br>#endif <br>#endif <br><br>#if $WCMODS?true:false$ <br>#if DEBUG <br>#warning local modification founded <br>#else <br>#error local modification founded <br>#endif <br>#endif</font></p>
<h4>5.&nbsp;修改项目属性</h4>
<p>&nbsp;&nbsp;&nbsp;&nbsp;在项目属性的Build Event页的Pre-build event command line中输入： <br><font color=#0000ff>"%ProgramFiles%\TortoiseSVN\bin\SubWCRev.exe" $(SolutionDir) $(ProjectDir)Properties\AssemblyInfo.template.cs $(ProjectDir)Properties\AssemblyInfo.cs -f <br></font>注意，这里我们必须保证TortoiseSVN安装到了默认路径上。在多人参加的项目中这应该是强制性的要求，否则，大家安装的路径都不一样，甲机器上能用的配置，到了乙机器上可能就不行了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;然后，你可能还需要将Publish页中的Automatically increment revision with each publish选项关掉（我不确定这步是否必须）。C#可以自己递增版本号，但它生成的版本号和代码库中的代码没有对应关系，我个人觉得意义不大。并且它还可能会把我们的版本自增机制搞乱。所以应该关掉。</p>
<h4>6.&nbsp;把项目加入版本库</h4>
<p>&nbsp;&nbsp;&nbsp;&nbsp;使用VisualSVN的Add solution to Subversion命令把项目加入SVN，但不要提交。</p>
<h4>7.&nbsp;从SVN中排除AssemblyInfo.cs文件</h4>
<p>&nbsp;&nbsp;&nbsp;&nbsp;每次编译时，这个文件都会基于AssemblyInfo.template.cs重新生成，所以没必要加入版本库。这步做完之后就可以提交整个项目了。</p>
<img src="http://www.cppblog.com/images/vckbase_com/localvar/1234/o_image004.jpg">
<h4>8.&nbsp;编译</h4>
<p>&nbsp;&nbsp;&nbsp;&nbsp;编译完成后，看一下生成的autover.exe文件的版本信息，本例中是1.0.0.1。随便改点什么，提交，重新编译，你会发现它自动变成了1.0.0.2，也就是程序的修订号总是与生成它的代码的修订号一致。这样，当程序出问题后，我们通过这个数字就能轻松得到生成它的那一版代码了。</p>
<img src="http://www.cppblog.com/images/vckbase_com/localvar/1234/o_image005.jpg">
<h4>9.&nbsp;其它问题</h4>
<p>&nbsp;&nbsp;&nbsp;&nbsp;第8步中大家做完修改后再编译时可能会看到警告或错误信息，说代码有本地修改或混合版本。这就是第4步中，在AssemblyInfo.template.cs文件最后加的两段代码的作用，它们检测代码是否都已经提交了并且版本是否一致，一旦发现问题就会在调试版中生成警告信息，在发布版中生成错误信息。使用这种方法，我们可以基本消除发布的程序的版本和代码的版本出现不一致的可能性。去掉这两个错误或警告的方法也很简单，把代码整体提交或更新一下就行了。</p>
<img src="http://blog.vckbase.com/localvar/aggbug/33718.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132755.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2008-05-20 09:12 <a href="http://www.cppblog.com/localvar/archive/2008/05/20/132755.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个更改键盘映射的小工具</title><link>http://www.cppblog.com/localvar/archive/2008/02/28/132757.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Thu, 28 Feb 2008 01:20:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2008/02/28/132757.html</guid><description><![CDATA[倒霉lenovo居然认为page up/page down的使用频率高于home/end，上网找到了这个小工具，可以重新映射键盘（只改注册表，不驻留内存）。怕以后找不到了，放自己blog上备份一下。<br><a href="http://www.mympc.org/down/1/2005-11-26_0111998067.html">原始链接</a><br><a href="http://blog.vckbase.com/Files/localvar/kbmap.zip">我的备份</a><img src="http://blog.vckbase.com/localvar/aggbug/32806.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132757.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2008-02-28 09:20 <a href="http://www.cppblog.com/localvar/archive/2008/02/28/132757.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>再记自己的两个常识性错误</title><link>http://www.cppblog.com/localvar/archive/2008/01/08/132759.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Tue, 08 Jan 2008 03:58:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2008/01/08/132759.html</guid><description><![CDATA[<p>1. WSAStartup只要每个进程调用一次就行了<br>&nbsp;&nbsp;&nbsp; 不知为什么, 几年以来，我一直认为要为每个使用网络的线程调一次. 直到今天才发现弄错了, 按说我一直是仔细阅读msdn的, 唉! 不过为每个线程调一次只是多余的, 并不是错误的, 也许这就是我一直没有注意到它的原因吧.<br>2. do while循环中的continue会跳到哪里</p>
<div style="BORDER-BOTTOM: windowtext 0.5pt solid; BORDER-LEFT: windowtext 0.5pt solid; PADDING-BOTTOM: 4px; PADDING-LEFT: 5.4pt; WIDTH: 98%; PADDING-RIGHT: 5.4pt; BACKGROUND: #e6e6e6; BORDER-TOP: windowtext 0.5pt solid; BORDER-RIGHT: windowtext 0.5pt solid; PADDING-TOP: 4px">
<div><span style="COLOR: #0000ff">do</span><span style="COLOR: #000000">&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_3_42_Closed_Text></span><span id=Codehighlighter1_3_42_Open_Text><span style="COLOR: #000000">{<br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;①</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">continue</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;②</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">}</span></span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(&nbsp;i&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">&nbsp;);</span></div>
</div>
<p>&nbsp;&nbsp;&nbsp; 一直认为是①, 今天正在写的程序出错了才发现是②. 老天保佑以前的程序不出错吧<img border=0 src="http://www.cppblog.com/Emoticons/QQ/02.gif" width=20 height=20>. 这个错误一直没发现的原因有两点，一是我用do while循环比较少, 里面有continue的更少; 二是自己偷懒了, 想当然了, 其实以前怀疑过它的结果的, 但觉得①更符合逻辑就没有深究.</p>
<p>&nbsp;&nbsp;&nbsp; 犯了错误总是比较郁闷的, 不过能在一个上午认识到这样两个错误，也算收获不小了。</p>
<img src="http://blog.vckbase.com/localvar/aggbug/31689.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132759.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2008-01-08 11:58 <a href="http://www.cppblog.com/localvar/archive/2008/01/08/132759.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows下配置SVN 1.4.5 + APACHE 2.2.6使用域认证</title><link>http://www.cppblog.com/localvar/archive/2007/12/20/132760.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Thu, 20 Dec 2007 06:28:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2007/12/20/132760.html</guid><description><![CDATA[<div>&nbsp;&nbsp;&nbsp; 其实在网上搜索这个主题，已经有很多文章了，而且Subversion和TortoiseSVN的文档上也有相关介绍。但在我自己配置的过程中，发现它们好像都不完全对。所以我觉得有必要把自己摸索的过程写出来，供大家参考。不过已经有那么多&#8220;前车之鉴&#8221;了，我的方法是否真的有用，只能靠老天保佑了。<br>&nbsp;&nbsp;&nbsp; 要想配置成功，首先要保证Apache、Svn和mod_auth_sspi这几个模块的版本是匹配的。我最开始就是在这上面栽的跟头。Apache有很多个版本（以2.0.x和2.2.x最常见），作为对应，每个版本的svn都有一些子版本与其匹配。例如1.4.5版的svn就有针对2.0.x和2.2.x的两个子版本。不幸的是，网上搜到的svn下载链接多是指向针对Apache 2.0.x的那个子版本，当把它用在最新版（目前是2.2.6）的Apache上时，出问题就是必然的了。实际上，当使用2.2.x版的Apache时，我们应该到<a href="http://subversion.tigris.org/servlets/ProjectDocumentList?expandFolder=91&amp;folderID=9246" target=_blank>这里</a>，点击左侧的文件夹<a href="http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=8100&amp;expandFolder=8100&amp;folderID=9246" target=_blank>Windows Apache 2.2.x</a>（等以后有了新版的apache，可能就是其它对应的文件夹了），然后在右侧的文件列表中下载对应得svn（我下载的是<a href="http://subversion.tigris.org/downloads/1.4.5-win32/apache-2.2/svn-win32-1.4.5.zip" target=_blank>svn-win32-1.4.5.zip</a>）。mod_auth_sspi我们也下载针对2.2.x版apache的那个就可以了。<br>&nbsp;&nbsp;&nbsp; 以下是我的安装配置过程，它是针对apache2.2.6和svn1.4.5的，如果你用的是其它版本，可能一些细节上会有所不同。<br>&nbsp;&nbsp;&nbsp; 分别安装apache和svn（svn就是把压缩包解开就行），然后把svn\bin文件夹下的mod_dav_svn.so、mod_authz_svn.so、libdb44.dll和intl3_svn.dll拷贝到apache的modules文件夹下，mod_auth_sspi中的mod_auth_sspi.so也拷贝到那去。<br>&nbsp;&nbsp;&nbsp; 最后是修改apache的配置文件httpd.conf，经过我的试验，最后确定使用下面配置文件就行了（其中背景标红的内容你可能需要根据你的实际情况进行修改）。</div>
<table style="BORDER-COLLAPSE: collapse" border=1 cellSpacing=0 borderColor=#999999 cellPadding=0 width="75%" bgColor=#f1f1f1>
    <tbody>
        <tr>
            <td>
            <p style="LINE-HEIGHT: 150%; MARGIN: 5px"><code><span style="COLOR: #000000"><span style="COLOR: #0000ff">ThreadsPerChild</span> 250<br><span style="COLOR: #0000ff">MaxRequestsPerChild</span> 0<br><br><span style="COLOR: #0000ff">ServerRoot</span> <span style="COLOR: #ff00ff">"<font style="BACKGROUND-COLOR: #ff0000" color=#000000>C:/Program Files/Apache Software Foundation/Apache2.2</font>"</span><br><span style="COLOR: #0000ff">ServerName</span> <font style="BACKGROUND-COLOR: #ff0000">svnserver.mydomain.net<span style="COLOR: #0000cc">:</span>8080</font><br><span style="COLOR: #0000ff">ServerSignature</span> <span style="COLOR: #ff0000">Off</span><br><span style="COLOR: #0000ff">ServerTokens</span> Prod<br><span style="COLOR: #0000ff">DocumentRoot</span> <span style="COLOR: #ff00ff">"htdocs"</span><br><span style="COLOR: #0000ff">Listen</span> <font style="BACKGROUND-COLOR: #ff0000">8080</font><br><br><span style="COLOR: #0000ff">LoadModule</span> sspi_auth_module modules/mod_auth_sspi.so<br>#<span style="COLOR: #0000ff">LoadModule</span> auth_basic_module modules/mod_auth_basic.so<br>#<span style="COLOR: #0000ff">LoadModule</span> auth_digest_module modules/mod_auth_digest.so<br>#<span style="COLOR: #0000ff">LoadModule</span> authn_file_module modules/mod_authn_file.so<br><span style="COLOR: #0000ff">LoadModule</span> authz_svn_module modules/mod_authz_svn.so<br><span style="COLOR: #0000ff">LoadModule</span> dir_module modules/mod_dir.so<br><span style="COLOR: #0000ff">LoadModule</span> deflate_module modules/mod_deflate.so<br><span style="COLOR: #0000ff">LoadModule</span> mime_module modules/mod_mime.so<br><span style="COLOR: #0000ff">LoadModule</span> setenvif_module modules/mod_setenvif.so<br><span style="COLOR: #0000ff">LoadModule</span> dav_module modules/mod_dav.so<br><span style="COLOR: #0000ff">LoadModule</span> dav_svn_module modules/mod_dav_svn.so<br><br><span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #0000ff">Directory</span> /<span style="COLOR: #0000cc">&gt;</span><br>&nbsp;&nbsp;<span style="COLOR: #0000ff">Options</span> <span style="COLOR: #ff0000">FollowSymLinks</span><br>&nbsp;&nbsp;<span style="COLOR: #0000ff">AllowOverride</span> <span style="COLOR: #ff0000">None</span><br><span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #0000cc">/</span><span style="COLOR: #0000ff">Directory</span><span style="COLOR: #0000cc">&gt;</span><br><br><span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #0000ff">IfModule</span> dir_module<span style="COLOR: #0000cc">&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">DirectoryIndex</span> index.html<br><span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #0000cc">/</span><span style="COLOR: #0000ff">IfModule</span><span style="COLOR: #0000cc">&gt;</span><br><br><span style="COLOR: #0000ff">ErrorLog</span> <span style="COLOR: #ff00ff">"<font style="BACKGROUND-COLOR: #ff0000" color=#000000>e:/svn/server.log</font>"</span><br><span style="COLOR: #0000ff">LogLevel</span> <span style="COLOR: #ff0000">error</span><br><br><span style="COLOR: #0000ff">DefaultType</span> text/plain<br><br><span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #0000ff">IfModule</span> mime_module<span style="COLOR: #0000cc">&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">TypesConfig</span> conf/mime.types<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">AddType</span> application/x-compress .Z<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">AddType</span> application/x-gzip .gz .tgz<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">AddType</span> application/x-x509-<span style="COLOR: #ff0000">ca</span><span style="COLOR: #ff0000">-</span>cert .crt<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">AddType</span> application/x-pkcs7-crl .crl<br><span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #0000cc">/</span><span style="COLOR: #0000ff">IfModule</span><span style="COLOR: #0000cc">&gt;</span><br><br><span style="COLOR: #0000cc"><font color=#000000># 注意&#8220;/svn/&#8221;中最后的斜杠是必须的, 否则列不出版本库列表<br># 访问时的url也要带着它, 想要去掉它可搜索RedirectMatch</font><br>&lt;</span><span style="COLOR: #0000ff">Location</span> <font style="BACKGROUND-COLOR: #ff0000">/svn/</font><span style="COLOR: #0000cc">&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;# configure SVN<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">DAV</span> svn<br>&nbsp;&nbsp;&nbsp;&nbsp;SVNListParentPath <span style="COLOR: #ff0000">on</span><br>&nbsp;&nbsp;&nbsp;&nbsp;# 版本库的根目录<br>&nbsp;&nbsp;&nbsp;&nbsp;SVNParentPath <font style="BACKGROUND-COLOR: #ff0000">e<span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">/</span>svn</font><br>&nbsp;&nbsp;&nbsp;&nbsp;# 权限控制文件<br>&nbsp;&nbsp;&nbsp;&nbsp;AuthzSVNAccessFile <font style="BACKGROUND-COLOR: #ff0000">e<span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">/</span>svn/authz</font><br>&nbsp;&nbsp;&nbsp;&nbsp;# 认证时的提示信息(中文不好使)<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">AuthName</span> <span style="COLOR: #ff00ff">"<font style="BACKGROUND-COLOR: #ff0000" color=#000000>My Subversion</font>"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;# 使用域认证<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">AuthType</span> SSPI<br>&nbsp;&nbsp;&nbsp;&nbsp;SSPIAuth <span style="COLOR: #ff0000">On</span><br>&nbsp;&nbsp;&nbsp;&nbsp;SSPIAuthoritative <span style="COLOR: #ff0000">On</span><br>&nbsp;&nbsp;&nbsp;&nbsp;# 指定使用那个域<br>&nbsp;&nbsp;&nbsp;&nbsp;SSPIDomain <font style="BACKGROUND-COLOR: #ff0000">mydomain.net</font><br>&nbsp;&nbsp;&nbsp;&nbsp;# 是否省略掉用户id的域名部分(好像只是影响svn的一些日志记录)<br>&nbsp;&nbsp;&nbsp;&nbsp;SSPIOmitDomain <span style="COLOR: #ff0000">On</span><br>&nbsp;&nbsp;&nbsp;&nbsp;# 是否允许非IE客户端(必须打开)<br>&nbsp;&nbsp;&nbsp;&nbsp;SSPIOfferBasic <span style="COLOR: #ff0000">On</span><br>&nbsp;&nbsp;&nbsp;&nbsp;# 基本认证(非域认证方式)具有更高的优先级?<br>&nbsp;&nbsp;&nbsp;&nbsp;SSPIBasicPreferred <span style="COLOR: #ff0000">Off</span><br>&nbsp;&nbsp;&nbsp;&nbsp;# 用户名大小写<br>&nbsp;&nbsp;&nbsp;&nbsp;SSPIUsernameCase lower<br>&nbsp;&nbsp;&nbsp;&nbsp;# 用户必须通过认证<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">Require</span> valid-<span style="COLOR: #0000ff">user</span><br><span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #0000cc">/</span><span style="COLOR: #0000ff">Location</span><span style="COLOR: #0000cc">&gt;</span></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
&nbsp;&nbsp;&nbsp; 最后如果大家觉得手工编辑那个权限控制文件（authz）很麻烦的话，也有一个取巧的办法，就是使用visualsvn server，虽然它目前还不支持域认证，但是我们可以借用它的权限管理界面。操作如下（假设版本库的根目录是e:\svn，并且权限控制文件的名字这时必须用authz）：<br>1）&nbsp;按前面的操作安装好apache和svn，但不要启动apache<br>2）&nbsp;把e:\svn改名为e:\svn1<br>3）&nbsp;<a href="http://www.visualsvn.com/server" target=_blank>下载</a>并安装visualsvn server，安装时指定版本库根目录为e:\svn<br>4）&nbsp;停掉并禁用visualsvn server的服务（VisualSVNServer），删除e:\svn<br>5）&nbsp;把e:\svn1的名字改回e:\svn<br>6）&nbsp;启动apache<br>7）&nbsp;启动visualsvn server的管理界面，把要使用这个版本库的所有人的域帐号都添加到它的用户列表中去（密码不会被实际使用，随便设或留空都行）。<br>8）&nbsp;万事ok了，设置权限吧！<br>
<div><br>ps: 2008-05-23<br>tortoisesvn(1.4.8版)文档中关于使用多认证源的描述中有一个错误，其中的<font color=#ff0000>AuthAthoritative</font><font color=#000000>和</font><font color=#ff0000>AuthAuthoritative<font color=#000000>都应该改成</font><font color=#ff0000>AuthBasicAuthoritative</font></font><font color=#000000>。另外，多认证源还要求域用户登录时必须用&#8220;domain\user&#8221;的形式，只输user部分就会用其他认证方式。所以，如果你按我前面的描述用了visual svn server，增加多认证源后，域用户的密码就千万不要留空了，因为那样不用密码就能登录了。<br></font></div>
<img src="http://blog.vckbase.com/localvar/aggbug/31427.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132760.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2007-12-20 14:28 <a href="http://www.cppblog.com/localvar/archive/2007/12/20/132760.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>介绍一下Subversion</title><link>http://www.cppblog.com/localvar/archive/2007/12/18/132761.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Tue, 18 Dec 2007 02:42:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2007/12/18/132761.html</guid><description><![CDATA[<div align=left>本来是发在公司内刊上的，现在拿来这里凑个数。</div>
<div align=left>&nbsp;</div>
<div align=left>&nbsp;&nbsp;&nbsp; 前一段时间，公司讨论统一配置管理工具时，我推荐了svn（subversion）。照理说，在公司已经使用了vss、cvs和ClearCase三种工具的情况下，再提一种基本没人用过的新工具不是什么明智的选择。但我确实觉得svn的优点很突出，值得一荐。下面我就对svn进行一下简单介绍，让各位同事对其有一个初步的了解。</div>
<h4>1.&nbsp;与其他工具的对比</h4>
<div>&nbsp;&nbsp;&nbsp; vss是我用的最多的配置工具，所以我相信每个用过vss的人都会对它的离线操作功能头疼不已。虽然它允许在与服务器断开的情况下修改文件，但重新连接后必须非常小心的处理每个文件，一旦出错，就会造成不小的麻烦。svn则没有这个问题。二者更详细的区别我会在下一节说明，这里就不多啰嗦了。<br>&nbsp;&nbsp;&nbsp; svn相对cvs是有明显优势的，因为svn的设计目标之一就是&#8220;一个更好的cvs&#8221;。而且，从众多开源项目的反映看，它也确实达到了这个目标：06年，最大的开源网站SourceForge开始支持svn；KDE和GNOME的开发团队也已经换用svn；如果大家多注意一下的话，还会发现更多著名的开源项目使用了svn。<br>&nbsp;&nbsp;&nbsp; ClearCase我没有实际使用过，按说应该无权评价。不过，我没有用过它的原因是因为它太难用了，曾经学过几天，但后来觉得太过复杂，就转向vss了。相比之下，svn是比较简单的，我大概花了一两天的时间就可以完成基本操作了，用的比较熟练也不过两周。另外就是ClearCase要钱，而svn是免费的。<br>&nbsp;&nbsp;&nbsp; 下表是这几种工具的对比，列出的功能都是我比较关心的。更详细的比较，大家可以看看<a href="http://better-scm.berlios.de/comparison/">http://better-scm.berlios.de/comparison/</a>。</div>
<div>
<table border=1 cellSpacing=1 cellPadding=1 width="75%">
    <tbody>
        <tr>
            <td>
            <p align=center><strong>项目</strong></p>
            </td>
            <td>
            <p align=center><strong>Vss</strong></p>
            </td>
            <td>
            <p align=center><strong>Clearcase</strong></p>
            </td>
            <td>
            <p align=center><strong>Cvs</strong></p>
            </td>
            <td>
            <p align=center><strong>svn</strong></p>
            </td>
        </tr>
        <tr>
            <td>&nbsp;文件/目录的重命名或移动</td>
            <td>
            <p align=center>是?</p>
            </td>
            <td>
            <p align=center>是</p>
            </td>
            <td>
            <p align=center>否</p>
            </td>
            <td>
            <p align=center>是</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left>&nbsp;原子提交</p>
            </td>
            <td>
            <p align=center>否</p>
            </td>
            <td>
            <p align=center>是</p>
            </td>
            <td>
            <p align=center>否</p>
            </td>
            <td>
            <p align=center>是</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left>&nbsp;变更集</p>
            </td>
            <td>
            <p align=center>否</p>
            </td>
            <td>
            <p align=center>可间接实现</p>
            </td>
            <td>
            <p align=center>否</p>
            </td>
            <td>
            <p align=center>是</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left>&nbsp;中文支持</p>
            </td>
            <td>
            <p align=center>是</p>
            </td>
            <td>
            <p align=center>未知</p>
            </td>
            <td>
            <p align=center>差</p>
            </td>
            <td>
            <p align=center>是</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left>&nbsp;visual studio集成</p>
            </td>
            <td>
            <p align=center>是</p>
            </td>
            <td>
            <p align=center>是</p>
            </td>
            <td>
            <p align=center>是</p>
            </td>
            <td>
            <p align=center>是</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left>&nbsp;eclipse集成</p>
            </td>
            <td>
            <p align=center>未知</p>
            </td>
            <td>
            <p align=center>未知</p>
            </td>
            <td>
            <p align=center>是</p>
            </td>
            <td>
            <p align=center>是</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left>&nbsp;http访问</p>
            </td>
            <td>
            <p align=center>8.0支持</p>
            </td>
            <td>
            <p align=center>差</p>
            </td>
            <td>
            <p align=center>是&nbsp;</p>
            </td>
            <td>
            <p align=center>是&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left>&nbsp;离线操作</p>
            </td>
            <td>
            <p align=center>差</p>
            </td>
            <td>
            <p align=center>未知&nbsp;</p>
            </td>
            <td>
            <p align=center>是&nbsp;</p>
            </td>
            <td>
            <p align=center>是&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left>&nbsp;权限管理</p>
            </td>
            <td>
            <p align=center>是</p>
            </td>
            <td>
            <p align=center>是&nbsp;</p>
            </td>
            <td>
            <p align=center>较差&nbsp;</p>
            </td>
            <td>
            <p align=center>是&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left>&nbsp;易用性</p>
            </td>
            <td>
            <p align=center>简单</p>
            </td>
            <td>
            <p align=center>复杂</p>
            </td>
            <td>
            <p align=center>较简单</p>
            </td>
            <td>
            <p align=center>较简单</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left>&nbsp;授权</p>
            </td>
            <td>
            <p align=center>商业</p>
            </td>
            <td>
            <p align=center>商业&nbsp;</p>
            </td>
            <td>
            <p align=center>GPL&nbsp;</p>
            </td>
            <td>
            <p align=center>Apache/BSD&nbsp;</p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<h4>2.&nbsp;svn能解决哪些问题</h4>
<div>&nbsp;&nbsp;&nbsp; 一直以来，XXXX项目都是使用vss作为配置管理工具的，但应用过程中我也越来越感觉到vss满足不了项目的需要，所以决定在项目组内试用svn，并在合适的时机完全转换到svn。具体说来，svn可以解决以下几个（包括但不限于<img border=0 src="http://www.cppblog.com/Emoticons/QQ/smile.gif" width=20 height=20>）问题。</div>
<h5>2.1.&nbsp;获取某个以前的版本</h5>
<div>&nbsp;&nbsp;&nbsp; 我想获得三天前签入的某个版本怎么办？在vss中，如果没有打标签，那可能就只有一个文件一个文件的去找了。规定每次签入都打个标签或许是个解决办法，不过这项规定能否很好的执行就是另一个问题了。在svn中，每次签入（准确地说应该是&#8220;提交&#8221;）都会为整个代码库生成一个确定的版本，所以能够轻松完成此任务。</div>
<h5>2.2.&nbsp;自动递增版本号</h5>
<div>&nbsp;&nbsp;&nbsp; XXXX发布后，现场经常会反馈回来一些问题。但我发现这些问题中有不少是由于程序版本不匹配或没有用最新的程序造成的。所以我就想在编译过程中实现一个自增版本号的功能，每次修改后，能自动生成一个版本号，并且能把它显示在程序的关于对话框等位置，这样工程人员就能直接把这些原因造成的问题排除掉了。让我失望的是vss做不到这一点，虽然它有&#8220;关键字扩展（keyword expansion）&#8221;功能，但实现不了我的需求。而如果要求每次编译前手工修改版本号，就是另外一个能否切实执行的问题，我对这类问题的总是很悲观的。<br>&nbsp;&nbsp;&nbsp; 前面已经说过，在svn中，每次签入（提交）都会为整个代码库生产一个版本。生成它的同时，svn还会为其指定一个递增的修订号，利用这个修订号和一个配套的工具（SubWCRev)，就可以做到自动生成版本号了。</div>
<h5>2.3.&nbsp;变更集</h5>
<div>&nbsp;&nbsp;&nbsp; 作为项目经理或设计人员，大家可能还会经常希望知道某个开发人员的某次签入到底修改了哪些内容，这一点在vss中也是做不到的。而在svn中，只要比较签入前的版本和签入后的版本就行了。实际上，在svn中，你可以比较任意两个版本之间的区别，甚至能追查到一个文件中每行代码的责任人。</div>
<h5>2.4.&nbsp;离线操作</h5>
<div>&nbsp;&nbsp;&nbsp; 这个在前面已经说过了，再提一次是想强调一下我有多希望配置管理工具支持此功能。</div>
<h3>3.&nbsp;相关工具和网站</h3>
<div><strong>TortoiseSvn：</strong>是windows下功能最强、最实用的svn客户端。它与资源管理器的右键菜单集成，可以管理包括源代码在内的任何文件。它的&#8220;图标叠加（Icon Overlay）&#8221;功能，可以让我们从文件和文件夹的图标中直观的看出它们的状态，如是否被修改等。另外，前面提到的SubWCRev就是它的一部分。<br><strong>AnkhSvn：</strong>一个visual studio的svn插件，支持svn的大部分功能，并且比较好用。<br><strong>VisualSvn：</strong>也是一个visual studio的svn插件，应该比AnkhSvn好一些，不过它是商业软件。</div>
<div><strong>VisualSvn Server：</strong>windows下svn+apache的组合，提供了一个mmc的管理界面，喜欢gui界面的人的福音。而且，虽然它和VisualSvn是同一家公司的产品，但它是免费的。<br><strong>Subclipse：</strong>eclipse的svn插件，也已经很成熟，据说使用风格和eclipse自带的cvs插件非常像。<br><strong>p4merge：</strong>这是一个文件对比/合并工具，TortoiseSvn自带的文件比较工具还比较好用，但合并工具就差点了，起码没有vss的好用。能找到的工具大多只支持双视图合并。p4merge则能支持三视图甚至四视图，用起来方便很多。开发这个工具的公司也是做配置管理软件的，不过这个公司比较好，只对它的服务器端收费，其他工具都可以免费用。<br><a href="http://www.tigris.org/"><strong>http://www.tigris.org/</strong></a><strong>：</strong>这是subversion、TortoiseSvn、AnkhSvn以及其它众多开源软件开发管理工具的官方站点。<br><a href="http://www.subversion.org.cn/"><strong>http://www.subversion.org.cn/</strong></a><strong>：</strong>svn中文网站。<br><a href="http://www.iusesvn.com/"><strong>http://www.iusesvn.com/</strong></a><strong>：</strong>也是一个svn的中文网站，内容和上一个有很多是重复的。<br></div>
<div></div>
<img src="http://blog.vckbase.com/localvar/aggbug/31344.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132761.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2007-12-18 10:42 <a href="http://www.cppblog.com/localvar/archive/2007/12/18/132761.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>锁？不锁？如何锁？</title><link>http://www.cppblog.com/localvar/archive/2007/10/15/132762.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Mon, 15 Oct 2007 01:46:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2007/10/15/132762.html</guid><description><![CDATA[<div>&nbsp;&nbsp;&nbsp; 加锁、解锁(同步/互斥)是多线程中非常基本的操作，但我却看到不少的代码对它们处理的很不好。简单说来有三类问题，一是加锁范围太大，虽然避免了逻辑错误，但锁了不该锁的东西，难免降低程序的效率；二是该锁的不锁，导致各种莫名其妙的错误；三是加锁方式不合适，该用临界区的用内核对象等，也会降低程序的效率。<br>&nbsp;&nbsp;&nbsp; 要正确的运用锁操作，首先要弄清楚什么时候需要加锁。很多书上都说在可能&#8220;同时发生多个写操作&#8221;或&#8220;同时发生读写操作&#8221;时，应该加锁。这固然没什么错，但我认为它没有说到问题的根上，更准确的表述应该是：如果不加锁会导致不可容忍的数据不一致，那么就应该加锁。据此，我在下表中列出了多线程中应该加锁和无需加锁的条件，其中的&#8220;简单数据类型&#8221;是指cpu可以在一条指令中完成操作的数据类型，一般整形和所有比整形小的数据类型都是，除此之外的类型都属于&#8220;复杂数据类型&#8221;，例如你自己定义的结构体等。<br>
<table style="WIDTH: 590px; HEIGHT: 87px" border=1 cellSpacing=1 cellPadding=1 width=590>
    <tbody>
        <tr>
            <td>&nbsp;</td>
            <td>&nbsp;操作的结果与初值无关</td>
            <td>&nbsp;操作的结果与初值相关</td>
        </tr>
        <tr>
            <td>&nbsp;写简单数据类型</td>
            <td>&nbsp;不需要加锁①</td>
            <td>&nbsp;需要加锁②</td>
        </tr>
        <tr>
            <td>&nbsp;写复杂数据类型</td>
            <td>&nbsp;需要加锁③</td>
            <td>&nbsp;需要加锁④</td>
        </tr>
        <tr>
            <td>&nbsp;读简单数据类型</td>
            <td>&nbsp;不需要加锁⑤</td>
            <td>&nbsp;不需要加锁⑥</td>
        </tr>
        <tr>
            <td>&nbsp;读复杂数据类型</td>
            <td>&nbsp;需要加锁⑦</td>
            <td>&nbsp;需要加锁⑧</td>
        </tr>
    </tbody>
</table>
</div>
&nbsp;&nbsp;&nbsp; 大家可能注意到，在第1、5、6种情况下，我认为可以不加锁，粗看起来，这与书上的说法有些矛盾。其实却不然，因为这些操作可以在一条指令内完成，所以它们具有天然的&#8220;原子性&#8221;，我们可以认为cpu已经给它们加锁了，我们没必要再画蛇添足。如果这个理由还不够的话，你不妨想一下我们再加一次锁是否有用，看下面的代码(以第1种情况为例)：
<table style="BORDER-COLLAPSE: collapse" border=1 cellSpacing=0 borderColor=#999999 cellPadding=0 width="75%" bgColor=#f1f1f1>
    <tbody>
        <tr>
            <td>
            <p style="LINE-HEIGHT: 150%; MARGIN: 5px"><code><span style="COLOR: #000000">Lock<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span> <span style="COLOR: #ff9900">// ①<br></span>n <span style="COLOR: #0000cc">=</span> 10<span style="COLOR: #0000cc">;</span> <span style="COLOR: #ff9900">// ②<br></span>Unlock<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span> <span style="COLOR: #ff9900">// ③<br></span><span style="COLOR: #0000ff">int</span> x <span style="COLOR: #0000cc">=</span> n<span style="COLOR: #0000cc">;</span> <span style="COLOR: #ff9900">// ④</span></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
看出来了吗？不管语句①③是否存在，这段代码执行完毕后，我们都无法保证x的值是10。也许你会想如果把③④两条语句的位置换一下，x就肯定是10了。可是在这个例子中，想让x是10，为什么不把语句④直接换成&#8220;int x = 10;&#8221;呢？既省了加锁，有减少了键盘的磨损，何乐而不为？！而且，我的这个例子并不是刻意构造的，在多线程，这种情况比比皆是。 <br>&nbsp;&nbsp;&nbsp; 第2种情况的典型代表是&#8220;i++;&#8221;，需要对它加锁是因为它表面上虽然只有一条语句，却要执行至少两个操作，一是读出i的初始, 二是把加一后的结果写回去，两个操作就没有&#8220;原子性&#8221;了，所以需要加锁。<br>&nbsp;&nbsp;&nbsp; 另外，上表中判断是否需要加锁的依据是&#8220;是否可能造成数据不一致&#8221;。实际上，有些情况下数据不一致是可以容忍的,如果它发生概率极低、造成的不良后果可以忽略、并能很快自动恢复，那它可能就是可以容忍的。对这种数据不一致，我们可以不加锁。不过对它的判定与程序的实际情况关联太大，我们在这里就不讨论了。<br>&nbsp;&nbsp;&nbsp; 加锁的方法也可分为三类，临界区、内核对象和互锁函数。相比前两类，互锁函数的知名度要低不少，但它却是我用的最多的方法，因为它有一个最大的优点：快！有不少书上比较临界区和内核对象时都说临界区的优点是不会进入内核模式，速度快。不过这是不全面的，如果没有冲突(实际发生冲突的概率一般很低)，临界区确实不会进内核模式，但如果发生了冲突要进行等待，它就要依靠内核对象了。而互锁函数则绝不会进内核模式，所以互锁函数是最快的(临界区在没有冲突时的行为是依靠互锁函数实现的)。互锁函数的缺点是只能处理相对简单的数据类型(不要和我前面说的&#8220;简单数据类型&#8221;等价起来)，但另一方面，对加锁需求最高的也往往是这些类型的数据。<br>&nbsp;&nbsp;&nbsp; 实际开发中，还有一种锁比较常用，这就是单写多读锁，《windows核心编程》上有一个单写多读锁的实现，我的blog上有另一个实现。前者适用于需加锁的对象数量较少(例如如只有一个)，访问冲突概率相对较高的情况。后者适用于需加锁的对象很多，访问冲突概率很低的情况(对象多了, 单个对象的访问冲突自然就少了)。两个实现的共同缺点是不支持重入，即同一个线程中，解锁前不能再次加锁。临界区在这方面有优势，它支持重入。使用TLS(线程局部存储)技术进行改进应该能让它们支持重入，不过这样做了以后我那个实现应该就算不上轻量级了:)。<br>&nbsp;&nbsp;&nbsp; 最后，还有其它的一些不用锁的方法也可以保证多线程中的数据一致性，其中最常用的就是循环。例如下面的例子：<br>
<table style="BORDER-COLLAPSE: collapse" border=1 cellSpacing=0 borderColor=#999999 cellPadding=0 width="75%" bgColor=#f1f1f1>
    <tbody>
        <tr>
            <td>
            <p style="LINE-HEIGHT: 150%; MARGIN: 5px"><code><span style="COLOR: #000000"><span style="COLOR: #0000ff">struct</span> bar<br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">volatile</span> <span style="COLOR: #0000ff">unsigned</span> version<span style="COLOR: #0000cc">;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff9900">// 一个额外的版本号字段<br></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">int</span> field1<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">char</span> field2<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">char</span> field3<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><br><span style="COLOR: #0000cc">}</span><span style="COLOR: #0000cc">;</span><br>bar g_bar <span style="COLOR: #0000cc">=</span> <span style="COLOR: #0000cc">{</span> 0 <span style="COLOR: #0000cc">}</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #ff9900"></span></span></code></p>
            <p style="LINE-HEIGHT: 150%; MARGIN: 5px"><code><span style="COLOR: #000000"><span style="COLOR: #ff9900">// 写线程<br></span><span style="COLOR: #0000cc">+</span><span style="COLOR: #0000cc">+</span>g_bar<span style="COLOR: #0000cc">.</span>version<span style="COLOR: #0000cc">;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff9900">// 加1, version是奇数, 表示正在更新<br></span>g_bar<span style="COLOR: #0000cc">.</span>field1 <span style="COLOR: #0000cc">=</span> 10<span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><br><span style="COLOR: #0000cc">+</span><span style="COLOR: #0000cc">+</span>g_bar<span style="COLOR: #0000cc">.</span>version<span style="COLOR: #0000cc">;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff9900">// 再加1, version是偶数, 表示更新完毕<br></span><br><span style="COLOR: #ff9900">// 读线程<br></span><span style="COLOR: #0000ff">void</span> ReadGlobalBar<span style="COLOR: #0000cc">(</span> bar<span style="COLOR: #0000cc">*</span> p <span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">unsigned</span> ver<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">do</span> <span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ver <span style="COLOR: #0000cc">=</span> g_bar<span style="COLOR: #0000cc">.</span>version<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">if</span><span style="COLOR: #0000cc">(</span> ver <span style="COLOR: #0000cc">%</span> 2 <span style="COLOR: #0000cc">!</span><span style="COLOR: #0000cc">=</span> 0 <span style="COLOR: #0000cc">)</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff9900">// 正在更新<br></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff0000">Sleep</span><span style="COLOR: #0000cc">(</span> 0 <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff9900">// 等待<br></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">continue</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>field1 <span style="COLOR: #0000cc">=</span> g_bar<span style="COLOR: #0000cc">.</span>field1<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><span style="COLOR: #0000cc">.</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span> <span style="COLOR: #0000ff">while</span><span style="COLOR: #0000cc">(</span> ver <span style="COLOR: #0000cc">!</span><span style="COLOR: #0000cc">=</span> g_bar<span style="COLOR: #0000cc">.</span>version <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span></span></code></p>
            <p style="LINE-HEIGHT: 150%; MARGIN: 5px"><code><span style="COLOR: #000000"><font face=新宋体><span style="COLOR: #0000cc">}</span></font></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
然而这种方法真的没用锁吗？看你怎么理解了，那个version字段其实就可以看做是锁的。不过它只是半个锁，因为它只锁了读操作，而没锁写操作，也就是说写操作可以随时进行而无需等待。如果读操作非常多，但写操作较少，并且你不希望写操作经常被打断，那它正好满足你的要求。它的缺点是你要保证系统中某个时刻最多有一个&#8220;writer&#8221;，&#8220;writer&#8221;一多，它就的无能为力了(这时一般应该用单写多读锁)。
<div><br><strong>2007.10.18：补充一点，关于acquire release semantics</strong><br>&nbsp;&nbsp; 在多处理器平台上，一个处理器的实际的操作顺序，和其它处理器所看到的它的操作顺序可能并不相同，例如：<br>a++;<br>b++;<br>在其他处理器看来，很有可能&#8220;b++&#8221;发生在前面，而&#8220;a++&#8221;发生在后面。某些情况下，其他处理器看到的顺序必须和实际的顺序保持一致，所以就需要引入acquire semantics和release semantics了。<br>&nbsp;&nbsp; 说一个操作具有acquire semantics，就表示可以保证其它处理器在看到这一操作的结果前，不会看到(该处理器上)后续操作的结果，对该处理器而言，可以理解为它进行此操作前，不会进行后续操作；而一个操作具有release semantics，就表示可以保证其它处理器在看到这一操作的结果前，能看到(该处理器)上先前所有操作的结果，对该处理器而言，可以理解为在完成所有先前的操作之前，不会进行此操作。<br>&nbsp;&nbsp; vc编译器(其它编译器不一定保证)保证对volatile对象的写操作具有release semantics；对volatile对象的读操作具有acquire semantics。基于此点保证，多线程环境中就可以用volatile型对象实现锁操作了。<br><br><a id=CategoryEntryList1_EntryStoryList_Entries__ctl12_TitleUrl href="http://www.cppblog.com/localvar/archive/2005/10/22/13826.html"><font color=#006666>对windows互锁函数的补充</font></a><br><a id=CategoryEntryList1_EntryStoryList_Entries__ctl6_TitleUrl href="http://www.cppblog.com/localvar/archive/2007/01/23/24160.html"><font color=#006666>一个轻量级的单写多读锁</font></a></div>
<img src="http://blog.vckbase.com/localvar/aggbug/29995.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132762.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2007-10-15 09:46 <a href="http://www.cppblog.com/localvar/archive/2007/10/15/132762.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一岁</title><link>http://www.cppblog.com/localvar/archive/2007/07/27/132763.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Fri, 27 Jul 2007 00:52:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2007/07/27/132763.html</guid><description><![CDATA[小家伙今天一周岁了。这一年，她实现了那么多的突破，第一次笑，第一次翻身，第一次爬，第一次站立.....，每一次都会让我和老婆兴奋不已。现在，她已经能很清晰的发出&#8220;爸爸&#8221;的声音了，虽然她还未必知道这两个字的含义，但我已经感动的不得了了，那种由衷的欣慰，是以前从未体会过的，或许这就是为人父母的不同吧。<img src="http://blog.vckbase.com/localvar/aggbug/27769.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132763.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2007-07-27 08:52 <a href="http://www.cppblog.com/localvar/archive/2007/07/27/132763.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>发布一个小程序(围棋方面的)</title><link>http://www.cppblog.com/localvar/archive/2007/06/11/132775.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Mon, 11 Jun 2007 01:27:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2007/06/11/132775.html</guid><description><![CDATA[昨天整理家当时想起来的，从最早开始写到现在已经将近10年了，最后一次修改也是7年前的事了，发上来做个纪念吧。很多地方实现的很难看，但对初学者应该还有些参考价值。昨天稍微改了一下，能在vs2005下编译通过了，不过由于当时赶&#8220;时髦&#8221;，用了direct sound，但现在我机器上没有directx的库了，所以只好把相关的部分都注释了，后果就是音效部分没有了，落子时没有声音，语音提示也没了。<br>对围棋爱好者，这个程序可能也有点用，它支持双人对弈、打谱等功能，还自带了200局棋谱。<br>这个程序，我不维护了，所以有任何问题，请不要找我<img border=0 src="http://www.cppblog.com/Emoticons/QQ/13.gif" width=20 height=20>。<a href="http://cid-cdf8c6a11ba3c6c6.office.live.com/self.aspx/.Public/blog/winwq.zip"><br><br>源码下载</a><img src="http://blog.vckbase.com/localvar/aggbug/26853.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132775.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2007-06-11 09:27 <a href="http://www.cppblog.com/localvar/archive/2007/06/11/132775.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>也发个智力题：转桌问题</title><link>http://www.cppblog.com/localvar/archive/2007/06/08/132776.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Fri, 08 Jun 2007 02:36:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2007/06/08/132776.html</guid><description><![CDATA[<p><font color=#000000>&nbsp;&nbsp;&nbsp; 一张正方形的可以旋转的桌子，每个角上有一个坑，坑中各放一只杯子，杯子口可以朝上或朝下，但四只杯子各自的初始状态未知。<br>&nbsp;&nbsp;&nbsp; 现在蒙住测试者的双眼，旋转桌子，当桌子停止转动后，测试者可以伸手摸任意两只杯子，得知它们的状态，并任意决定是否翻转它们（即每次可以翻转0只、1只或2只杯子），但测试者一旦选定了要触摸的杯子，就不能更改。之后，再次旋转桌子.....，直到所有杯子口全部朝上或全部朝下。<br>问：测试者最多经过多少次旋转就可以确保游戏结束。<br></font>答案（把后面选中就看到了）：<font color=#ffffff size=1 face=Garamond>5次，不过,更重要的是如何操作<img border=0 src="http://www.cppblog.com/Emoticons/QQ/noidea.gif" width=20 height=20></font></p>
<img src="http://blog.vckbase.com/localvar/aggbug/26818.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132776.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2007-06-08 10:36 <a href="http://www.cppblog.com/localvar/archive/2007/06/08/132776.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>纪念我的智齿</title><link>http://www.cppblog.com/localvar/archive/2007/04/28/132777.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Sat, 28 Apr 2007 06:13:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2007/04/28/132777.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp; 昨天（4月27日）下午，一颗跟随我十几年的智齿被拔掉了，虽然它留给我的大多数记忆都是塞和剔，但失去总会有一点异样的感觉，少了一颗牙的我还是原来的我吗？<br>&nbsp;&nbsp;&nbsp; 整个过程比我想象的快的多，也就2分钟。麻药的劲过去之后也没多疼，不过出血量超出我的想象，昨天前半夜都没睡着，每过一会就是一嘴血。初步估计流了100cc+，早晨起来照镜子差点被自己满嘴满脸是血的样子吓到。今天咬了一上午的棉球，总算止住了。<br>&nbsp;&nbsp; 智齿每次只能拔一边的，另外一颗，要等这边长好了才能拔，五一之后还有另一次考验。<br>&nbsp;&nbsp; 不过还是要友情提示大家，智齿长歪了，一定要早去正规医院（拔智齿很复杂，弄不好的话很危险）看是否应该拔掉，即使不疼。我的这颗已经把它的邻居顶坏了，那颗牙能不能保住还很难说。<br><br>6月12日，左边这颗也拔了。这次用了10分钟，才弄下来，动了锤子，牙被打碎了，不能留下来做纪念了。还缝了针。有段时间挺疼的，不过坚持着没吃止痛药。<br><img src="http://blog.vckbase.com/localvar/aggbug/25830.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132777.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2007-04-28 14:13 <a href="http://www.cppblog.com/localvar/archive/2007/04/28/132777.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>调试托管代码调用的本机代码</title><link>http://www.cppblog.com/localvar/archive/2007/04/17/132778.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Tue, 17 Apr 2007 06:32:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2007/04/17/132778.html</guid><description><![CDATA[本来不是什么大问题，不过鉴于我对.net的熟悉程度，和半天的时间，还是记录一下。另外blog也好久没更新了，顺便刷一篇。<br><br>本问题涉及到两个模块: a.dll: c++编写，本机代码；b.exe: c#编写，托管代码。b调用a，运行时有点问题，但不确定是哪边的原因，故开始debug。但发现，不管是从a启动还是从b启动，调试器都跟不进a的源代码。浪费一上午的时间后发现，进行如下设置即可：<br>如果从a启动，&#8220;a的项目属性|Debugging|Debugger Type&#8221;必须设为&#8220;Mixed&#8221;或&#8220;Native Only&#8221;。这一点上我一开始被默认值&#8220;Auto&#8221;给误导了，以为调试器会智能选择，没想到它&#8220;大智若愚&#8221;。<br>如果从b启动，则需要选中&#8220;b的项目属性|Debug|Enable unmanaged code debugging&#8221;。<br><br><br>另外C#调用COM时传递数组的方法，参见：<a href="http://support.microsoft.com/kb/305990/zh-cn">http://support.microsoft.com/kb/305990/zh-cn</a><img src="http://blog.vckbase.com/localvar/aggbug/25538.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132778.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2007-04-17 14:32 <a href="http://www.cppblog.com/localvar/archive/2007/04/17/132778.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>我的一个错误&amp;友情提示: 不要定义原型相同但实现不同的同名内联函数</title><link>http://www.cppblog.com/localvar/archive/2007/02/14/132779.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Wed, 14 Feb 2007 03:31:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2007/02/14/132779.html</guid><description><![CDATA[<div>最早是在下面的程序中发现的问题:</div>
<table style="BORDER-COLLAPSE: collapse" border=1 cellSpacing=0 borderColor=#999999 cellPadding=0 width="75%" bgColor=#f1f1f1>
    <tbody>
        <tr>
            <td>
            <p style="LINE-HEIGHT: 150%; MARGIN: 5px"><code><span style="COLOR: #000000"><span style="COLOR: #ff9900">// a.cpp<br></span><span style="COLOR: #0000ff">struct</span> foo<br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">void</span> bar<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000cc">{</span> <span style="COLOR: #ff0000">printf</span><span style="COLOR: #0000cc">(</span><span style="COLOR: #ff00ff">"foo::bar in a.cpp\n"</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span> <span style="COLOR: #0000cc">}</span><br><span style="COLOR: #0000cc">}</span><span style="COLOR: #0000cc">;</span><br><br><span style="COLOR: #0000ff">void</span> testa<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;foo f<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;f<span style="COLOR: #0000cc">.</span>bar<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #ff9900">// b.cpp<br></span><span style="COLOR: #0000ff">struct</span> foo<br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">void</span> bar<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000cc">{</span> <span style="COLOR: #ff0000">printf</span><span style="COLOR: #0000cc">(</span><span style="COLOR: #ff00ff">"foo::bar in b.cpp\n"</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span> <span style="COLOR: #0000cc">}</span><br><span style="COLOR: #0000cc">}</span><span style="COLOR: #0000cc">;</span><br><br><span style="COLOR: #0000ff">void</span> testb<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;foo f<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;f<span style="COLOR: #0000cc">.</span>bar<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #ff9900">// main.cpp<br></span><span style="COLOR: #0000ff">int</span> main<span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000ff">int</span> argc<span style="COLOR: #0000cc">,</span> <span style="COLOR: #0000ff">char</span><span style="COLOR: #0000cc">*</span><span style="COLOR: #0000cc">*</span> argv <span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;testa<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;testb<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span></span></code></p>
            <p style="LINE-HEIGHT: 150%; MARGIN: 5px"><code><span style="COLOR: #000000"><span style="COLOR: #0000cc">&nbsp; return 0;</span><br><span style="COLOR: #0000cc">}</span><span style="COLOR: #0000cc">;</span></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
结果我发现这个程序居然输出:<br>foo::bar in a.cpp<br>foo::bar in a.cpp<br>先怀疑是编译器的bug, 不过很快否定了(因为编译阶段并不管具体链接的符号). 继而怀疑是链接器的bug, 但最后发现还是我的bug, 因为上面的代码实际上等价于
<table style="BORDER-COLLAPSE: collapse" border=1 cellSpacing=0 borderColor=#999999 cellPadding=0 width="75%" bgColor=#f1f1f1>
    <tbody>
        <tr>
            <td>
            <p style="LINE-HEIGHT: 150%; MARGIN: 5px"><code><span style="COLOR: #000000"><span style="COLOR: #ff9900">// test.h<br></span><span style="COLOR: #0000ff">struct</span> foo<br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">inline</span> <span style="COLOR: #0000ff">void</span> bar<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">}</span><span style="COLOR: #0000cc">;</span><br><br><span style="COLOR: #ff9900">// a.cpp<br></span><span style="COLOR: #0000cc">#</span><span style="COLOR: #ff0000">include</span> <span style="COLOR: #ff00ff">"test.h"</span><br><span style="COLOR: #0000ff">inline</span> <span style="COLOR: #0000ff">void</span> foo<span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">:</span>bar<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000cc">{</span> <span style="COLOR: #ff0000">printf</span><span style="COLOR: #0000cc">(</span><span style="COLOR: #ff00ff">"foo::bar in a.cpp\n"</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span> <span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #0000ff">void</span> testa<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;foo f<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;f<span style="COLOR: #0000cc">.</span>bar<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #ff9900">// b.cpp<br></span><span style="COLOR: #0000cc">#</span><span style="COLOR: #ff0000">include</span> <span style="COLOR: #ff00ff">"test.h"</span><br><span style="COLOR: #0000ff">inline</span> <span style="COLOR: #0000ff">void</span> foo<span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">:</span>bar<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000cc">{</span> <span style="COLOR: #ff0000">printf</span><span style="COLOR: #0000cc">(</span><span style="COLOR: #ff00ff">"foo::bar in b.cpp\n"</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span> <span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #0000ff">void</span> testb<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;foo f<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;f<span style="COLOR: #0000cc">.</span>bar<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #ff9900">// main.cpp<br></span><span style="COLOR: #0000ff">int</span> main<span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000ff">int</span> argc<span style="COLOR: #0000cc">,</span> <span style="COLOR: #0000ff">char</span><span style="COLOR: #0000cc">*</span><span style="COLOR: #0000cc">*</span> argv <span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;testa<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;testb<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span></span></code></p>
            <p style="LINE-HEIGHT: 150%; MARGIN: 5px"><code><span style="COLOR: #000000"><span style="COLOR: #0000cc">&nbsp;&nbsp;return 0;</span><br><span style="COLOR: #0000cc">}</span><span style="COLOR: #0000cc">;</span></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
由于foo::bar是inline的, 所以允许每个编译单元有一个自己的实现, 但在链接阶段, 链接器是不可能发现这两个实现不同的(理论上可能,但工作量太大了), 所以它会假设实现相同(毕竟大家一般都把inline函数写在头文件中), 并把所有的引用指向同一个实现(如果分别指向本编译单元内部自有的实现肯定是错的, 考虑函数中定义了静态变量的情形), 这也就出现了本文中的问题. 如果foo::bar不是inline的, 则会有一个链接错误.<br>这里bar是作为一个成员函数出现的, 但它是非成员函数也有同样的问题, 所以结论就是: 不要在同一个名字空间中定义原型相同但实现不同的同名内联函数.<br><br>ps: 狗年最后一篇，祝大家新春愉快，万事如意，合家欢乐.<img src="http://blog.vckbase.com/localvar/aggbug/24589.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132779.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2007-02-14 11:31 <a href="http://www.cppblog.com/localvar/archive/2007/02/14/132779.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>vs2005编译的程序不能运行的几个解决方法</title><link>http://www.cppblog.com/localvar/archive/2007/01/31/132734.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Wed, 31 Jan 2007 08:34:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2007/01/31/132734.html</guid><description><![CDATA[<div>&nbsp;&nbsp;&nbsp; 这两天有点焦头烂额, 我们这边运行的好好的程序, 到了测试的机器上就不能启动(是根本运行不了, 而不是运行出错), 弄得我异常郁闷. 经过了一番摸索, 发现和winxp、win2003中为解决dll hell而引入的manifest机制有关系. 而以前我们用vs2003开发, 它并没有强制程序使用manifest, 但到了vs2005中, 这已经改成必需的了, 而我们并没有按照需要进行相关的配置, 所以程序启动不了了. 根据目前的经验, vs2005编译的程序不能启动大致有两个原因, 下面简单介绍解决办法.<br><strong>1. 在开发组的机器上(安装有vs2005)有时都不能启动<br></strong>&nbsp;&nbsp;&nbsp; 这一般是项目的文件被放在了fat/fat32分区上导致的, 解决方法是把它们都移动到ntfs分区上, 或者把&#8220;项目属性|Manifest Tool|General|Use FAT32 Work-around&#8221;设为yes.<br><strong>2. 开发组运行正常, 换到其它机器上就不行了</strong><br>&nbsp;&nbsp;&nbsp; 这一般就是系统dll(包括crt,mfc,atl等)没有正确配置导致的. 如果程序是release版, 那么很简单, 只要把&#8220;<vs2005安装文件夹 />\SDK\v2.0\BootStrapper\Packages\vcredist_x86&#8221;下的"vcredist_x86.exe"拷贝到目标机器上运行即可, 这是以x86平台为例的, 如果你用的是别的cpu平台(amd64或ia64)把x86替换成相应的内容就可以了.<br>&nbsp;&nbsp;&nbsp; 如果是debug版, 就复杂一些了, 首先要确定你需要的dll的版本, 绝大多数(注意:不是"所有")情况下它和编译器的版本相同, 通过vs2005的关于对话框就能看到, 如下图所示:</div>
<img border=0 hspace=0 alt="" src="http://www.cppblog.com/images/vckbase_com/localvar/1120/o_vs2005.GIF">
<div>确定版本后, 在开发组的机器上进入&#8220;%windir%\winsxs"文件夹(下面将以<span style="COLOR: red">x86</span>平台<span style="COLOR: red">8.0.50727.762</span>版本的<span style="COLOR: red">debug crt</span>为例进行说明), 拷贝以下文件到目标机器的相同位置即可: <span style="COLOR: red"></span></div>
<div><span style="COLOR: red"></span>&nbsp;</div>
<div><span style="COLOR: red">x86</span>_Microsoft.VC80.<span style="COLOR: red">DebugCRT</span>_1fc8b3b9a1e18e3b_<span style="COLOR: red">8.0.50727.762</span>_x-ww_5490cd9f文件夹下的所有文件<br><br>Manifests文件夹下的<span style="COLOR: red">x86</span>_Microsoft.VC80.<span style="COLOR: red">DebugCRT</span>_1fc8b3b9a1e18e3b_<span style="COLOR: red">8.0.50727.762</span>_x-ww_5490cd9f.cat和<span style="COLOR: red">x86</span>_Microsoft.VC80.<span style="COLOR: red">DebugCRT</span>_1fc8b3b9a1e18e3b_<span style="COLOR: red">8.0.50727.762</span>_x-ww_5490cd9f.manifest<br><br>Policies\<span style="COLOR: red">x86</span>_policy.8.0.Microsoft.VC80.<span style="COLOR: red">DebugCRT</span>_1fc8b3b9a1e18e3b_x-ww_09e017b4文件夹下的<span style="COLOR: red">8.0.50727.762</span>.cat和 <span style="COLOR: red">8.0.50727.762</span>.policy<br><br>&nbsp;&nbsp;&nbsp; 注意, 上面的操作只是在目标操作系统为winxp,win2003及以上时才需要的, 如果是win2000及以下的系统, 只要把第一个文件夹下的文件拷贝到system32中就行了.<br><br></div>
<div><strong>附:<br></strong><br>msdn上有关vc应用程序部署的几片文章, 供参考<br><a href="http://msdn2.microsoft.com/en-us/library/ms235342.aspx">Troubleshooting C/C++ Isolated Applications and Side-by-side Assemblies</a><br><a href="http://msdn2.microsoft.com/en-us/library/ms235285(VS.80).aspx">Deployment Examples</a><br><br><br>以下是与这个问题相关的一些系统提示信息, 为了让碰到这些问题的人更容易搜到这篇文章, 我把它们列在这里.<br>参照的汇编没有安装在系统上<br>应用程序要求的组件版本同另一个活动的组件有冲突。<br>系统无法执行指定的程序<br>ERROR_SXS_ASSEMBLY_NOT_FOUND<br>14003<br>0x800736B3<br>The referenced assembly is not installed on your system. </div>
<img src="http://blog.vckbase.com/localvar/aggbug/24367.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132734.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2007-01-31 16:34 <a href="http://www.cppblog.com/localvar/archive/2007/01/31/132734.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个轻量级的单写多读锁</title><link>http://www.cppblog.com/localvar/archive/2007/01/23/132735.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Tue, 23 Jan 2007 12:41:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2007/01/23/132735.html</guid><description><![CDATA[<div>&nbsp;&nbsp;&nbsp; 与《windows核心编程》上的那个相比最大的优势是体积小, 它只有四个字节(《windows核心编程》上的那个至少是它的10倍), 如果你有大量对象需要进行单写多读访问的话, 它会比较适用. 缺点是它在加锁时使用的等待函数是Sleep, 如果访问冲突很多的话, 效率比较低. 代码如下(很简单, 就不多做解释了):<br></div>
<div><br><font color=#ff0000>发现代码里有个bug，参见<a href="http://www.cppblog.com/localvar/archive/2008/01/08/132759.html">http://www.cppblog.com/localvar/archive/2008/01/08/132759.html</a></font><font color=#ff0000>的第二条</font><font color=#ff0000>。时间有限，我暂时不改了，请大家自己注意一下。</font><br></div>
<table style="BORDER-COLLAPSE: collapse" border=1 cellSpacing=0 borderColor=#999999 cellPadding=0 width="75%" bgColor=#f1f1f1>
    <tbody>
        <tr>
            <td>
            <p style="LINE-HEIGHT: 150%; MARGIN: 5px"><code><span style="COLOR: #000000"><span style="COLOR: #ff9900">// 头文件<br></span><br><span style="COLOR: #0000cc">#</span><span style="COLOR: #ff0000">ifndef</span> SWMR_LOCK_H<br><span style="COLOR: #0000cc">#</span><span style="COLOR: #ff0000">define</span> SWMR_LOCK_H<br><br><span style="COLOR: #0000cc">#</span><span style="COLOR: #ff0000">ifndef</span> SWMR_LOCK_NUMBER_OF_WRITER<br><span style="COLOR: #0000cc">#</span><span style="COLOR: #ff0000">define</span> SWMR_LOCK_NUMBER_OF_WRITER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1<br><span style="COLOR: #0000cc">#</span><span style="COLOR: #ff0000">endif</span> <span style="COLOR: #ff9900">// SWMR_LOCK_NUMBER_OF_WRITER<br></span><br><span style="COLOR: #0000ff">typedef</span> <span style="COLOR: #0000ff">volatile</span> <span style="COLOR: #0000ff">long</span> SWMR_LOCK<br><br><span style="COLOR: #0000ff">void</span> SwmrLockInitialize<span style="COLOR: #0000cc">(</span> SWMR_LOCK<span style="COLOR: #0000cc">*</span> pLock <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000ff">void</span> SwmrLockWriteLock<span style="COLOR: #0000cc">(</span> SWMR_LOCK<span style="COLOR: #0000cc">*</span> pLock <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000ff">void</span> SwmrLockWriteUnlock<span style="COLOR: #0000cc">(</span> SWMR_LOCK<span style="COLOR: #0000cc">*</span> pLock <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000ff">void</span> SwmrLockReadLock<span style="COLOR: #0000cc">(</span> SWMR_LOCK<span style="COLOR: #0000cc">*</span> pLock <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000ff">void</span> SwmrLockReadUnlock<span style="COLOR: #0000cc">(</span> SWMR_LOCK<span style="COLOR: #0000cc">*</span> pLock <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000ff">void</span> SwmrLockUninitialize<span style="COLOR: #0000cc">(</span> SWMR_LOCK<span style="COLOR: #0000cc">*</span> pLock <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><br><span style="COLOR: #0000cc">#</span><span style="COLOR: #ff0000">endif</span> </span></code></p>
            </td>
        </tr>
    </tbody>
</table>
<p>--------------------------------------------------------------------------------</p>
<table style="BORDER-COLLAPSE: collapse" border=1 cellSpacing=0 borderColor=#999999 cellPadding=0 width="75%" bgColor=#f1f1f1>
    <tbody>
        <tr>
            <td>
            <p style="LINE-HEIGHT: 150%; MARGIN: 5px"><code><span style="COLOR: #000000"><span style="COLOR: #ff9900">// 实现文件<br></span><span style="COLOR: #0000cc">#</span><span style="COLOR: #ff0000">include</span> <span style="COLOR: #ff00ff">"srmrl.h"</span><br><br><span style="COLOR: #ff9900">////////////////////////////////////////////////////////////////////////////////<br></span><br><span style="COLOR: #0000cc">#</span><span style="COLOR: #ff0000">define</span> WRITING_FLAG&nbsp;&nbsp;&nbsp;&nbsp;0x40000000<br><br><span style="COLOR: #ff9900">////////////////////////////////////////////////////////////////////////////////<br></span><br><span style="COLOR: #0000ff">void</span> SwmrLockInitialize<span style="COLOR: #0000cc">(</span> SWMR_LOCK<span style="COLOR: #0000cc">*</span> pLock <span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">*</span>pLock <span style="COLOR: #0000cc">=</span> 0<span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #ff9900">////////////////////////////////////////////////////////////////////////////////<br></span><br><span style="COLOR: #0000ff">void</span> SwmrLockWriteLock<span style="COLOR: #0000cc">(</span> SWMR_LOCK<span style="COLOR: #0000cc">*</span> pLock <span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">long</span> old<span style="COLOR: #0000cc">,</span> xchg<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">do</span> <span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;old <span style="COLOR: #0000cc">=</span> <span style="COLOR: #0000cc">*</span>pLock<span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">#</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #0000cc">(</span> SWMR_LOCK_NUMBER_OF_WRITER <span style="COLOR: #0000cc">&gt;</span> 1 <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">if</span><span style="COLOR: #0000cc">(</span> old <span style="COLOR: #0000cc">&amp;</span> WRITING_FLAG <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff0000">Sleep</span><span style="COLOR: #0000cc">(</span> 0 <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">continue</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br><span style="COLOR: #0000cc">#</span><span style="COLOR: #ff0000">endif</span> <span style="COLOR: #ff9900">// ( SWMR_LOCK_NUMBER_OF_WRITER &gt; 1 )<br></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xchg <span style="COLOR: #0000cc">=</span> old <span style="COLOR: #0000cc">|</span> WRITING_FLAG<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span> <span style="COLOR: #0000ff">while</span><span style="COLOR: #0000cc">(</span> _InterlockedCompareExchange<span style="COLOR: #0000cc">(</span> pLock<span style="COLOR: #0000cc">,</span> xchg<span style="COLOR: #0000cc">,</span> old <span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000cc">!</span><span style="COLOR: #0000cc">=</span> old <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff9900">// wait until all readers quit reading<br></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">while</span><span style="COLOR: #0000cc">(</span> old <span style="COLOR: #0000cc">!</span><span style="COLOR: #0000cc">=</span> WRITING_FLAG <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff0000">Sleep</span><span style="COLOR: #0000cc">(</span> 0 <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;old <span style="COLOR: #0000cc">=</span> <span style="COLOR: #0000cc">*</span>pLock<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br><span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #ff9900">////////////////////////////////////////////////////////////////////////////////<br></span><br><span style="COLOR: #0000ff">void</span> SwmrLockWriteUnlock<span style="COLOR: #0000cc">(</span> SWMR_LOCK<span style="COLOR: #0000cc">*</span> pLock <span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">*</span>pLock <span style="COLOR: #0000cc">=</span> 0<span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #ff9900">////////////////////////////////////////////////////////////////////////////////<br></span><br><span style="COLOR: #0000ff">void</span> SwmrLockReadLock<span style="COLOR: #0000cc">(</span> SWMR_LOCK<span style="COLOR: #0000cc">*</span> pLock <span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">long</span> old<span style="COLOR: #0000cc">,</span> xchg<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">do</span> <span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;old <span style="COLOR: #0000cc">=</span> <span style="COLOR: #0000cc">*</span>pLock<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">if</span><span style="COLOR: #0000cc">(</span> old <span style="COLOR: #0000cc">&amp;</span> WRITING_FLAG <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff0000">Sleep</span><span style="COLOR: #0000cc">(</span> 0 <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">continue</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xchg <span style="COLOR: #0000cc">=</span> old <span style="COLOR: #0000cc">+</span> 1<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span> <span style="COLOR: #0000ff">while</span><span style="COLOR: #0000cc">(</span> _InterlockedCompareExchange<span style="COLOR: #0000cc">(</span> pLock<span style="COLOR: #0000cc">,</span> xchg<span style="COLOR: #0000cc">,</span> old <span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000cc">!</span><span style="COLOR: #0000cc">=</span> old <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #ff9900">////////////////////////////////////////////////////////////////////////////////<br></span><br><span style="COLOR: #0000ff">void</span> SwmrLockReadUnlock<span style="COLOR: #0000cc">(</span> SWMR_LOCK<span style="COLOR: #0000cc">*</span> pLock <span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;_InterlockedDecrement<span style="COLOR: #0000cc">(</span> pLock <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">}</span><br><br><span style="COLOR: #ff9900">////////////////////////////////////////////////////////////////////////////////<br></span><br><span style="COLOR: #0000ff">void</span> SwmrLockUninitialize<span style="COLOR: #0000cc">(</span> SWMR_LOCK<span style="COLOR: #0000cc">*</span> pLock <span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;pLock<span style="COLOR: #0000cc">;</span> <span style="COLOR: #ff9900">// has nothing to do<br></span><br><span style="COLOR: #0000cc">}</span></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
<div></div>
<div></div>
<div></div>
<img src="http://blog.vckbase.com/localvar/aggbug/24160.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132735.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2007-01-23 20:41 <a href="http://www.cppblog.com/localvar/archive/2007/01/23/132735.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>sizeof的计算</title><link>http://www.cppblog.com/localvar/archive/2006/12/03/132736.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Sat, 02 Dec 2006 23:44:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2006/12/03/132736.html</guid><description><![CDATA[<font face=宋体>&nbsp;&nbsp;&nbsp; 论坛上经常有人问某个结构体的大小为什么与他预计的不一致, 对特定问题，我肯定能回答出来; 但要从总体上说出个子丑寅卯, 我就不行了. 今日闲来无事, 特地研究了一下, 总算将sizeof的计算方法大概梳理清楚了.</font>
<h3><span style="FONT-FAMILY: 宋体">1. 字节对齐</span></h3>
<p><span style="FONT-FAMILY: 宋体">&nbsp; &nbsp; 每种cpu都有其特定的字长, 如目前最常见的32位cpu, 其字长就是32位(4字节), 即将普及的64位cpu, 字长就是64位(8字节). 而cpu对内存的访问总是从字长的整数倍开始, 以字长为单位的. 例如(假设是32位cpu, 下同)读一个32位整数, 如果其起始地址是0, 则只需一次内存操作; 但如果起始地址是1、2或3, 则需要两次操作来将相关的两个字都读出来, 再在cpu内部进行处理才行. 对x86cpu, 这样做仅会稍微降低一点效率, 但如果是某些其它类型的cpu则可能会有成千上万倍的效率损失, 甚至是程序根本无法运行. </span></p>
<p><span style="FONT-FAMILY: 宋体">&nbsp; &nbsp; 从以上的分析可以看出, 我们定义结构体时, 为了提高效率和可移植性, 应该尽量让cpu以最少的内存操作访问其任意一个成员. 例如对于第一个成员是char型, 第二个成员是int型的结构, 其体积应该是5字节, 但显然在这种情况下cpu对int型成员的访问要两次内存操作, 而不是最少的一次. 所以我们应该浪费一些空间, 在char型成员后面加上3个填充字节, 使int型成员的起始位置对齐cpu字长的整数倍. 不过, 一个像回事的程序会有大量结构定义, 如果都去人为计算, 手工填充, 工作量就太大了. 因此, 编译器特意设置了一个选项(在vs2005中, 它是项目属性|c/c++|code generation|struct member alignment)来配置默认的字节对齐方式, 你可以选择1、2、4、8或者16字节对齐. 如果你什么也没有选的话, 它的默认值是8. 当然, 编译器也并没有搞一刀切, 对于需要特殊处理的结构, 你还可以使用"#pragma pack"编译指令单独为其指定其合适的对齐方式. 注意, 虽然我们从cpu字长引出了编译器的字节对齐, 但它们是两个不同的概念, 一定不要弄混. 从某种意义上, 你可以把字节对齐理解为: 我的程序将运行在字长是这个数值的cpu上.</span></p>
<h3><span style="FONT-FAMILY: 宋体">2. 简单结构</span></h3>
<p><span style="FONT-FAMILY: 宋体">&nbsp; &nbsp; 这里所说的简单结构, 是指仅由编译器内置类型构成的结构. 我们已经知道, 计算其体积, 需要其字节对齐设置, 这里假设其值是N. 则(有点拗口, 多读几遍):</span><br><span style="FONT-FAMILY: 宋体">&nbsp; &nbsp; 简单结构的大小, 是其符合"使cpu在任意情况下, 访问其任意成员的内存操作次数不大于'(sizeof(此成员) + N - 1)/N'(这里的除法使用的是C/C++整数除法的语意)"的所有内存布局中, 体积最小的那个占用的字节数.</span>&nbsp;<br><span style="FONT-FAMILY: 宋体">&nbsp; &nbsp; 例如结构：<br>&nbsp;&nbsp; &nbsp;<span style="COLOR: #0000ff">struct</span> A &nbsp; &nbsp; &nbsp; &nbsp; 和 &nbsp; &nbsp; &nbsp; &nbsp; <span style="COLOR: #3300ff">struct</span> B<br>&nbsp;&nbsp; &nbsp;{ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; {<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; <span style="COLOR: #3300ff">char</span> c; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="COLOR: #3300ff">double</span> d;<br>&nbsp; &nbsp; &nbsp;&nbsp; &nbsp;<span style="COLOR: #3300ff">double</span> d; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="COLOR: #3300ff">char</span> c;<br>&nbsp; &nbsp; }; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; };<br>其sizeof的结果与N的对应关系应该是:</span>
<p>
<div style="TEXT-ALIGN: center">
<table style="WIDTH: 60%">
    <tbody>
        <tr>
            <td style="WIDTH: 100px"><strong>N</strong></td>
            <td style="WIDTH: 100px"><strong>sizeof(A)</strong></td>
            <td style="WIDTH: 100px"><strong>sizoef(B)</strong></td>
        </tr>
        <tr>
            <td style="WIDTH: 100px">1</td>
            <td style="WIDTH: 100px">9</td>
            <td style="WIDTH: 100px">9</td>
        </tr>
        <tr>
            <td style="WIDTH: 100px">2</td>
            <td style="WIDTH: 100px">10</td>
            <td style="WIDTH: 100px">10</td>
        </tr>
        <tr>
            <td style="WIDTH: 100px; HEIGHT: 21px">4</td>
            <td style="WIDTH: 100px; HEIGHT: 21px">12</td>
            <td style="WIDTH: 100px; HEIGHT: 21px">12</td>
        </tr>
        <tr>
            <td style="WIDTH: 100px">8</td>
            <td style="WIDTH: 100px">16</td>
            <td style="WIDTH: 100px">16</td>
        </tr>
        <tr>
            <td style="WIDTH: 100px">16</td>
            <td style="WIDTH: 100px">16</td>
            <td style="WIDTH: 100px">16</td>
        </tr>
    </tbody>
</table>
</div>
<span style="FONT-FAMILY: 宋体"><br>&nbsp; &nbsp; A的结果我想大家都能计算出来, 就不多解释了. 但你可能会问: 当N&gt;1时, B的结果为什么不是9了呢? 它是9才是符合你上面的描述呀?! 这里你就要注意我所说的"任意情况"了, 如果我们总是使用单个的B, 那sizeof(B)总是9肯定没问题, 但问题是我们有时会定义一个B的数组, 如: <br>&nbsp; &nbsp; B array[2];<br>这时, 如果我们访问"array[1].d"会需要几次内存操作呢? 不用说, 它超过了"(sizeof(d) + N - 1)/N", 所以它的大小不能总是9.<br></span>
<h3><span style="FONT-FAMILY: 宋体">3. 复合结构</span></h3>
<p><span style="FONT-FAMILY: 宋体">&nbsp; &nbsp; &nbsp;与简单结构相对, 复合结构就是指那些部分或全部成员也是结构的结构. 其实没有必要把它单独列出来的, 因为其大小的计算方法与简单结构完全一样. 唯一要注意的就是: 对其每个成员的大小的计算要按定义这个成员的类型时的字节对齐来进行, 而不能按定义这个复合结构时的对齐设置. 例如:</span> <br><span style="FONT-FAMILY: 宋体">&nbsp; &nbsp; <span style="COLOR: #3300ff">#pragma pack</span>( <span style="COLOR: #3300ff">push</span>, 8 )<br>&nbsp; &nbsp; <span style="COLOR: #3300ff">struct</span> A<br>&nbsp; &nbsp; {<br>&nbsp;&nbsp; &nbsp; &nbsp;&nbsp; <span style="COLOR: #3300ff">char</span> c;<br>&nbsp;&nbsp; &nbsp; &nbsp;&nbsp; &nbsp;<span style="COLOR: #3300ff">double</span> d;<br>&nbsp; &nbsp; };<br>&nbsp; &nbsp; <span style="COLOR: #3300ff">#pragma pack</span>( 1 )<br>&nbsp; &nbsp; <span style="COLOR: #3300ff">struct</span> B<br>&nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; &nbsp; <span style="COLOR: #3300ff">char</span> c;<br>&nbsp;&nbsp; &nbsp; &nbsp;&nbsp; &nbsp;A a;<br>&nbsp; &nbsp; };<br>&nbsp; &nbsp; <span style="COLOR: #3300ff">#pragma pack</span>( <span style="COLOR: #3300ff">pop</span> )<br>sizeof(A)和sizeof(B), 将分别是16和17, 而不是16和10.</span>
<h3><span style="FONT-FAMILY: 宋体">4. 特殊情况</span></h3>
<p><span style="FONT-FAMILY: 宋体">&nbsp;&nbsp; &nbsp;结构体的大小还有几种特殊情况, 一是空结构, 即没有任何成员的结构, 这种情况, 编译器规定其大小是1; 二是如果结构有虚函数, 则它会包含一个虚函数表指针(vfptr, 但这只是一般情况, 具体取决与编译器实现), 它的大小等于cpu字长, 但由于不能直接从定义中看出来, 你数的时候一定不要把它忘了; 还有就是虚拟继承等情况, 不过它们的结果与编译器实现关联太严重, 并且通常也碰不到, 这里就不做讨论了.</span></p>
<p><span style="FONT-FAMILY: 宋体">PS: 只是大概想了这么多, 如果哪里说错了, 欢迎大家批评指正.</span></p>
<img src="http://blog.vckbase.com/localvar/aggbug/23337.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132736.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2006-12-03 07:44 <a href="http://www.cppblog.com/localvar/archive/2006/12/03/132736.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一种引用计数机制的实现</title><link>http://www.cppblog.com/localvar/archive/2006/11/26/132737.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Sun, 26 Nov 2006 08:49:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2006/11/26/132737.html</guid><description><![CDATA[<div>&nbsp;&nbsp;&nbsp; 毫无疑问, 引用计数是一种非常有效的动态控制对象生命周期的机制. 我们最熟悉的引用计数实现可能就要数COM的AddRef和Release了. 但这种机制也有明显的缺点, 那就是无法实现对对象死亡时间的精确控制: 调用Release后, 就失去了对对象的控制, 虽然对象可能会被立即杀掉, 但我们无法保证这一点. 也许程序的其他地方还对它拥有引用, 并且还会有一系列的AddRef和Release, 而只要计数不降到0, 对象就一直活着, 甚至可能比你我更长寿<img border=0 src="http://www.cppblog.com/Emoticons/QQ/15.gif" width=20 height=20>.</div>
<div>&nbsp;</div>
<div>&nbsp;&nbsp;&nbsp; 为了更好的说明这一点, 请考虑下面的情况: 我们有某种类型的对象, 这种对象在程序运行过程中会不断的被创建和杀死, 而所有活着的对象都被放在一个全局表格中. 由于表格拥有一个对象的引用, 所以表格中不被程序其它部分使用的对象的计数将为1. 当程序要访问某个对象时, 就会通过一个键值从表格中找到它, 递增其引用计数, 待访问完毕后, 再递减计数. 从以上可以看出, 我们要想杀掉一个对象, 只要去掉表格对它的引用(也就是把引用计数减一)就可以了. 但这并不能确保对象被杀死, 因为程序的其它地方仍能从表格中找到它, 并增加其计数; 更进一步, 我们可以在去掉表格的引用后, 把对象从表格中删除, 这样计数就不会增加了, 但很不幸, 我们并不是在任何时候都能这样做, 有些时候没有"彻底死亡"的对象是不能从表格中删除的.</div>
<div>&nbsp;</div>
<div>&nbsp;&nbsp;&nbsp; 那有没有两全其美的方法呢? 应该说还是有的. 引用计数通常用一个32位整数来表示, 它最大能支持几十亿个引用, 但实践上, 能达到的最大值要远小于这个数字, 所以, 我们可以把其中的某些位挪作它用, 用来表示对象是否已经被杀掉, 而不能再增加新的引用. 看下面的实现:</div>
<div>&nbsp;</div>
<table style="BORDER-COLLAPSE: collapse" border=1 cellSpacing=0 borderColor=#999999 cellPadding=0 width="75%" bgColor=#f1f1f1>
    <tbody>
        <tr>
            <td>
            <p style="LINE-HEIGHT: 150%; MARGIN: 5px"><code><span style="COLOR: #000000"><span style="COLOR: #0000ff">template</span><span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #0000ff">class</span> T<span style="COLOR: #0000cc">&gt;</span><br><span style="COLOR: #0000ff">class</span> CRefCount<br><span style="COLOR: #0000cc">{</span><br><span style="COLOR: #0000ff">private</span><span style="COLOR: #0000cc">:</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff9900">// 使用第30位作为生存标志位, 你可以改成其它位, 但千万不要用了符号位<br></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">static</span> <span style="COLOR: #0000ff">const</span> <span style="COLOR: #0000ff">LONG</span> s_lAliveFlag <span style="COLOR: #0000cc">=</span> 0x40000000<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">volatile</span> <span style="COLOR: #0000ff">LONG</span> m_lRef<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<br><span style="COLOR: #0000ff">public</span><span style="COLOR: #0000cc">:</span><br>&nbsp;&nbsp;&nbsp;&nbsp;CRefCount<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000cc">:</span> m_lRef<span style="COLOR: #0000cc">(</span> s_lAliveFlag <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">bool</span> AddRef<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">LONG</span> lRef<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">do</span><span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lRef <span style="COLOR: #0000cc">=</span> m_lRef<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff9900">// 已经死亡了, 增加引用失败<br></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">if</span><span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000cc">(</span>lRef <span style="COLOR: #0000cc">&amp;</span> s_lAliveFlag<span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000cc">=</span><span style="COLOR: #0000cc">=</span> 0 <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">return</span> <span style="COLOR: #0000ff">false</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span> <span style="COLOR: #0000ff">while</span><span style="COLOR: #0000cc">(</span> InterlockedCompareExchange<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">&amp;</span>m_lRef<span style="COLOR: #0000cc">,</span> lRef<span style="COLOR: #0000cc">+</span>1<span style="COLOR: #0000cc">,</span> lRef<span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000cc">!</span><span style="COLOR: #0000cc">=</span> lRef <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">return</span> <span style="COLOR: #0000ff">true</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">void</span> Release<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">if</span><span style="COLOR: #0000cc">(</span> InterlockedDecrement<span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000cc">&amp;</span>m_lRef <span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000cc">=</span><span style="COLOR: #0000cc">=</span> 0 <span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T<span style="COLOR: #0000cc">*</span> pT <span style="COLOR: #0000cc">=</span> <span style="COLOR: #0000ff">static_cast</span><span style="COLOR: #0000cc">&lt;</span>T<span style="COLOR: #0000cc">*</span><span style="COLOR: #0000cc">&gt;</span><span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000ff">this</span> <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">delete</span> pT<span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">void</span> Suicide<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff9900">// 注意: 调用此函数前应AddRef, 这样调用之后的Release才能正确删除对象<br></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InterlockedAnd<span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000cc">&amp;</span>m_lRef<span style="COLOR: #0000cc">,</span> <span style="COLOR: #0000cc">~</span>s_lActiveFlag <span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000cc">}</span><br><span style="COLOR: #0000cc">}</span><span style="COLOR: #0000cc">;</span><br></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
<p>&nbsp;&nbsp;&nbsp; 程序很简单, 我就不做过多解释了, 但正像我在标题中写的, 它只是"一种引用计数的实现"方法而已, 和其他实现相比, 它既有优点, 也有缺点, 所以使用时一定要根据实际情况, 选择最合适的方法.</p>
<p><br>PS: InterlockedAnd在VS2005中是编译器的一个intrinsic, 如果你使用的编译器不支持它, 可参考我的《<a href="http://www.cppblog.com/localvar/archive/2005/10/22/132745.html" target=_blank>对windows互锁函数的补充</a>》, 自己实现一个.</p>
<img src="http://blog.vckbase.com/localvar/aggbug/23242.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132737.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2006-11-26 16:49 <a href="http://www.cppblog.com/localvar/archive/2006/11/26/132737.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>女儿百天</title><link>http://www.cppblog.com/localvar/archive/2006/11/04/132738.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Sat, 04 Nov 2006 07:08:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2006/11/04/132738.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 时间过的真快呀，小家伙百天了。不过跟她妈妈回老家去了，我不能亲自给她过了，这里祝她茁壮成长。回想这一百天, 劳累但充满幸福。真感谢她给我带来的快乐。<img src="http://blog.vckbase.com/localvar/aggbug/22973.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132738.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2006-11-04 15:08 <a href="http://www.cppblog.com/localvar/archive/2006/11/04/132738.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用派生类对象通过成员函数指针调用基类虚函数之不可能性的证明</title><link>http://www.cppblog.com/localvar/archive/2006/10/19/132739.html</link><dc:creator>局部变量</dc:creator><author>局部变量</author><pubDate>Thu, 19 Oct 2006 11:32:00 GMT</pubDate><guid>http://www.cppblog.com/localvar/archive/2006/10/19/132739.html</guid><description><![CDATA[<div>&nbsp;&nbsp;&nbsp; 希望大家没有被这么拗口的标题吓到:). 本文源于下面这个问题:</div>
<div>
<table style="BORDER-COLLAPSE: collapse" border=1 cellSpacing=0 borderColor=#999999 cellPadding=0 width="75%" bgColor=#f1f1f1>
    <tbody>
        <tr>
            <td>
            <p style="LINE-HEIGHT: 150%; MARGIN: 5px"><code><span style="COLOR: #000000"><font face=新宋体><span style="COLOR: #0000ff">struct</span> base<br><span style="COLOR: #0000cc">{</span><br>&nbsp;<span style="COLOR: #0000ff">void</span> foo<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><br>&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;<span style="COLOR: #ff0000">cout</span> <span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #0000cc">&lt;</span> <span style="COLOR: #ff00ff">"base::foo"</span> <span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #0000cc">&lt;</span> <span style="COLOR: #ff0000">endl</span><span style="COLOR: #0000cc">;</span><br>&nbsp;<span style="COLOR: #0000cc">}</span><br>&nbsp;<span style="COLOR: #0000ff">virtual</span> <span style="COLOR: #0000ff">void</span> bar<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><br>&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;<span style="COLOR: #ff0000">cout</span> <span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #0000cc">&lt;</span> <span style="COLOR: #ff00ff">"base::bar"</span> <span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #0000cc">&lt;</span> <span style="COLOR: #ff0000">endl</span><span style="COLOR: #0000cc">;</span><br>&nbsp;<span style="COLOR: #0000cc">}</span><br><span style="COLOR: #0000cc">}</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000ff">struct</span> derived <span style="COLOR: #0000cc">:</span> base<br><span style="COLOR: #0000cc">{</span><br>&nbsp;<span style="COLOR: #0000ff">virtual</span> <span style="COLOR: #0000ff">void</span> bar<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><br>&nbsp;<span style="COLOR: #0000cc">{</span><br>&nbsp;&nbsp;<span style="COLOR: #ff0000">cout</span> <span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #0000cc">&lt;</span> <span style="COLOR: #ff00ff">"derived::bar"</span> <span style="COLOR: #0000cc">&lt;</span><span style="COLOR: #0000cc">&lt;</span> <span style="COLOR: #ff0000">endl</span><span style="COLOR: #0000cc">;</span><br>&nbsp;<span style="COLOR: #0000cc">}</span><br><span style="COLOR: #0000cc">}</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000ff">int</span> __cdecl _tmain<span style="COLOR: #0000cc">(</span> <span style="COLOR: #0000ff">int</span> argc<span style="COLOR: #0000cc">,</span> _TCHAR<span style="COLOR: #0000cc">*</span> argv<span style="COLOR: #0000cc">[</span><span style="COLOR: #0000cc">]</span> <span style="COLOR: #0000cc">)</span><br><span style="COLOR: #0000cc">{</span><br>&nbsp;<span style="COLOR: #0000ff">void</span> <span style="COLOR: #0000cc">(</span>base<span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">*</span>pfn<span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000cc">=</span> <span style="COLOR: #0000cc">&amp;</span>base<span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">:</span>bar<span style="COLOR: #0000cc">;</span><br>&nbsp;derived d<span style="COLOR: #0000cc">;</span><br>&nbsp;d<span style="COLOR: #0000cc">.</span>base<span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">:</span>bar<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span> </font><font face=新宋体><span style="COLOR: #ff9900">// 1<br></span><br>&nbsp;<span style="COLOR: #0000cc">(</span>d<span style="COLOR: #0000cc">.</span>base<span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">:</span><span style="COLOR: #0000cc">*</span>pfn<span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span> </font><font face=新宋体><span style="COLOR: #ff9900">// 2 想实现和上一行一样的输出, 但是编译失败<br></span><br>&nbsp;<span style="COLOR: #0000ff">return</span> 0<span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000cc">}</span></font></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<div>&nbsp;&nbsp;&nbsp; 很明显, 标2的那一行是想使用派生类对象通过成员函数指针调用基类虚函数, 以实现与标1的那行相同的输出, 但却无法编译通过. 这是个语法错误, 因为"::"运算符的优先级高于 ".", 所以那一行会先计算"base::*pfn", 然而"*pfn"并不是"base"的成员, 故有错误时很自然的. 那么是否可以通过修改那条语句来达到目的呢? 分析了成员函数指针的实现后, 我发现, 至少在vc7.1和vc8上, 这是不可能的. 由于vc的标准兼容性已经非常高,所以我怀疑c++标准就不支持这种调用, 但没有证实.</div>
<div>&nbsp;&nbsp;&nbsp; 在上面的例子中, pfn指向的是虚函数bar, 但它也必须能指向普通成员函数foo. 当指向 foo时, 它保存的就是foo的入口地址; 然而当指向bar时, 直接保存这个地址就不行了,因为对base和derived来说, 这个地址并不相同. vc对此的解决方法是由编译器加入了一系列的内部函数"vcall". 一个类中的每个虚函数都有一个唯一与之对应的vcall函数, 但在不同类之间, 这些vcall实际上是公用的. pfn指向的就是这些vcall中的一个.</div>
<div>&nbsp;&nbsp;&nbsp; 我们知道, 调用成员函数时要传递this指针. 一般情况下, 它是通过ecx寄存器传递的, 所以vcall的实现如下所示:<br>
<table style="BORDER-COLLAPSE: collapse" border=1 cellSpacing=0 borderColor=#999999 cellPadding=0 width="75%" bgColor=#f1f1f1>
    <tbody>
        <tr>
            <td>
            <p style="LINE-HEIGHT: 150%; MARGIN: 5px"><code><span style="COLOR: #000000"><font face=新宋体><span style="COLOR: #0000ff">mov</span> <span style="COLOR: #ff0000">eax</span><span style="COLOR: #0000cc">,</span> <span style="COLOR: #ff0000">dword</span> <span style="COLOR: #0000ff">ptr</span><span style="COLOR: #0000cc">[</span><span style="COLOR: #ff0000">ecx</span><span style="COLOR: #0000cc">]</span><span style="COLOR: #0000cc">;</span><br><span style="COLOR: #0000ff">jmp</span> <span style="COLOR: #ff0000">dword</span> <span style="COLOR: #0000ff">ptr</span> <span style="COLOR: #0000cc">[</span><span style="COLOR: #ff0000">eax</span><span style="COLOR: #0000cc">+</span>xx<span style="COLOR: #0000cc">]</span></font></span></code></p>
            </td>
        </tr>
    </tbody>
</table>
第一句中, 由于ecx是this指针, 而一般vfptr是类的第一个成员, 所以它是把vfptr, 也就是vtable的地址存到了eax中. 第二句里面的xx, 在32位计算机上, 是4的整数倍, 所以这一句的意思是: 跳转到vtable的第xx/4项所指的地址上, 这个地址就是最终要调用的函数的入口.</div>
<div>&nbsp;&nbsp;&nbsp; 明白了虚成员函数指针的实现, 就可以看那种调用为什么不能实现了. 让我们用反证法, 如果它能实现, 为讨论方便就假设标2的那一句是正确的吧, 在进行调用时, 编译器首先要保证传递的是指向d的this指针, 然后还要保证this所指向的vfptr所指的是base 的vtable. 编译器能做到吗? 当然能, 它可以在调用前偷偷修改vfptr使其指向base的vtable, 并在调用返回后再把它恢复过来, 但想想这样做在多线程环境中的后果吧.&nbsp; 所以编译器是不可能这样做的, 也就是说"使用派生类对象通过成员函数指针调用基类虚函数是不可能的".<br><br><br>ps: 很早就写出来了，但一直忘了发:(</div>
<img src="http://blog.vckbase.com/localvar/aggbug/22811.html" width=1 height=1> 
<img src ="http://www.cppblog.com/localvar/aggbug/132739.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/localvar/" target="_blank">局部变量</a> 2006-10-19 19:32 <a href="http://www.cppblog.com/localvar/archive/2006/10/19/132739.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>