<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>原创</title><link>http://blog.vckbase.com/localvar/category/1212.html</link><description>原创</description><managingEditor>局部变量</managingEditor><dc:language>zh-CHS</dc:language><generator>.Text Version 0.958.2004.214</generator><item><dc:creator>局部变量</dc:creator><title>解决了一个困惑很久的bug</title><link>http://blog.vckbase.com/localvar/archive/2009/01/08/36194.html</link><pubDate>Thu, 08 Jan 2009 08:58:00 GMT</pubDate><guid>http://blog.vckbase.com/localvar/archive/2009/01/08/36194.html</guid><wfw:comment>http://blog.vckbase.com/localvar/comments/36194.html</wfw:comment><comments>http://blog.vckbase.com/localvar/archive/2009/01/08/36194.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://blog.vckbase.com/localvar/comments/commentRss/36194.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/localvar/services/trackbacks/36194.html</trackback:ping><description>&lt;p&gt;让这个bug困扰了很久，前一段太忙只找了个临时解决方案而没有追究原因，今天终于把它搞清楚了。由于测试时只在多cpu系统上出现，我甚至一度怀疑它是cpu的bug&lt;img title="大汗" alt="大汗" src="http://vckbase.com/bbs/image/emimg/010.gif"&gt; 。&lt;/p&gt; &lt;p&gt;两个c/s结构的网络通讯程序，服务器端使用完成端口模型，客户端使用阻塞模型，双方以一种客户端发送命令，服务器端处理，然后返回应答的方式通讯。问题出在服务器端。以下是服务器端代码的大致处理逻辑：&lt;/p&gt;&lt;pre&gt;&lt;span style="color: #0000ff"&gt;long&lt;/span&gt; &lt;span style="color: #0000ff"&gt;volatile&lt;/span&gt; g_busy = 0;
&lt;span style="color: #0000ff"&gt;void&lt;/span&gt; iocp_thread()
{
	&lt;span style="color: #0000ff"&gt;while&lt;/span&gt;( GetQueuedCompletionStatus() )
	{
		&lt;span style="color: #0000ff"&gt;if&lt;/span&gt;( InterlockedCompareExchange( &amp;amp;g_busy, 1, 0 ) != 0 )
			WSASend( "&lt;span style="color: #8b0000"&gt;服务器忙&lt;/span&gt;" );
		&lt;span style="color: #008000"&gt;// 处理命令&lt;/span&gt;
		ProcessCommand();
		WSASend( "&lt;span style="color: #8b0000"&gt;应答信息&lt;/span&gt;" );
		InterlockedExchange( &amp;amp;g_busy, 0 );
	}
}&lt;/pre&gt;
&lt;p&gt;其中ProcessCommand需要互斥运行（这是简化的逻辑，实际上有很多不同的命令，有些需要互斥，有些可以并行，否则就没必要用完成端口了），并且需要一定的时间才能处理完毕。为了避免多个客户端同时执行命令，导致所有的iocp线程都等在那，我把g_busy当成了一个锁，第一个线程可以成功进入，其它的都直接向客户端返回&amp;#8220;服务器忙&amp;#8221;。&lt;/p&gt;
&lt;p&gt;程序一直都运行的很好，直到有一天把服务器程序装到了一台有双核cpu的机器上。我发现，如果让客户端连续发送命令，即收到上一条命令的应答后立即发送下一条命令，就会随机的返回&amp;#8220;服务器忙&amp;#8221;，而这时只有一个客户端连接上去，按照我设想的逻辑是不可能出这种情况的。检查了半天代码，没觉得有什么问题，调试吧，又遇到了另一个难题，海森堡的测不准原理起作用了，做的工作太多问题就消失了，做的太少又得不到什么有价值的信息。搞得我很是头疼。&lt;/p&gt;
&lt;p&gt;今天再次看这个问题，突然想到：它肯定和线程切换相关，所以我应该记录下每次处理命令的线程的ID，这样出错时就可以看看上次成功执行命令的那个线程在干什么了。方法正确了，问题也就迎刃而解了，我发现，出问题时，上一个线程的WSASend居然还没有返回，也就是说，客户端已经收到应答并发送了下一条命令，服务器端也收到了命令并准备处理，但上一条命令的应答却还没有完全发送完成，难怪出错了！&lt;/p&gt;
&lt;p&gt;总结经验教训，感觉自己一开始被两点给误导了，一是实际程序中的WSARecv/WSASend藏的比较深，没这么明显，所以没注意到。二是当时粗略检查代码觉得没问题，就把主要精力放在ProcessCommand上了，由于我把它里面一段访问sql server的代码注释掉以后，问题就不出了，所以还看了半天atl oledb的源码，最后精疲力尽，其它事情又比较多就放弃了。&lt;/p&gt;&lt;img src ="http://blog.vckbase.com/localvar/aggbug/36194.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>局部变量</dc:creator><title>发布一个小工具：EasyDump</title><link>http://blog.vckbase.com/localvar/archive/2009/01/06/36183.html</link><pubDate>Tue, 06 Jan 2009 08:33:00 GMT</pubDate><guid>http://blog.vckbase.com/localvar/archive/2009/01/06/36183.html</guid><wfw:comment>http://blog.vckbase.com/localvar/comments/36183.html</wfw:comment><comments>http://blog.vckbase.com/localvar/archive/2009/01/06/36183.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://blog.vckbase.com/localvar/comments/commentRss/36183.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/localvar/services/trackbacks/36183.html</trackback:ping><description>&lt;P&gt;为了分析用户使用过程中出现的软件Bug，经常需要.dmp文件的帮助。一般我们会用WinDbg或adplus制作这个文件，可这两个工具都有点&amp;#8220;太难&amp;#8221;了，往往要费九牛二虎之力才能教会用户。而让程序在崩溃时自动转储或用Dr. Watson转储虽然使用简单，却只能做崩溃转储，对死锁之类的情况则无能为力。&lt;/P&gt;
&lt;P&gt;所以我决定自己写一个小工具降低一下制作.dmp文件的难度，也就有了今天发布的这个EasyDump（轻松转储）。代码和可执行文件都放到google code（也是刚注册的，尝试一下:)）上去了，大家可以到&lt;A title=http://code.google.com/p/easytools/ href="http://code.google.com/p/easytools/"&gt;http://code.google.com/p/easytools/&lt;/A&gt;下载。&lt;/P&gt;
&lt;P&gt;程序还没有很好的测试过，如果有bug的话，应该可以直接在项目主页上报告。另外下一步考虑增加三个功能：首先是异常过滤，因为first chance异常太多了！如果选择了生成.dmp的话，一秒钟可能就有十个甚至更多的文件，设置了异常过滤后，可以把一些不关心的异常屏蔽掉，不生成文件。其次是如果没有second chance的话，就把first chance的文件直接删掉，也有助于减少不必要的文件。第三是界面的国际化，也发布个英文版什么的。&lt;/P&gt;
&lt;P&gt;2009.01.08: 自动删除first chance文件的功能已经实现.&lt;BR&gt;2009.01.22: 异常过滤功能已经实现.&lt;/P&gt;&lt;img src ="http://blog.vckbase.com/localvar/aggbug/36183.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>局部变量</dc:creator><title>命令行下进行数字签名</title><link>http://blog.vckbase.com/localvar/archive/2008/11/18/35679.html</link><pubDate>Tue, 18 Nov 2008 03:26:00 GMT</pubDate><guid>http://blog.vckbase.com/localvar/archive/2008/11/18/35679.html</guid><wfw:comment>http://blog.vckbase.com/localvar/comments/35679.html</wfw:comment><comments>http://blog.vckbase.com/localvar/archive/2008/11/18/35679.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://blog.vckbase.com/localvar/comments/commentRss/35679.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/localvar/services/trackbacks/35679.html</trackback:ping><description>&lt;P&gt;网上介绍数字签名的文章，大多使用signtool的signwizard命令实现，这种方式虽说简单，却需要人为干预，不能自动执行。msdn上说signtool的sign命令可以在命令行中完成签名，但描述的相当模糊，试了半天，终于找到了它的使用方法，一共执行四条命令即可，前三条一次性执行，最后生成一个个人证书(pfx)，最后一条用于实际签名，可以放在post build event中去自动执行。&lt;/P&gt;
&lt;P&gt;1. makecert生成x.509证书和私钥, 会弹出界面要求输入两次密码, 我输的是123, 其中localvar studio是公司名&lt;BR&gt;makecert /sv sign.pvk /n "CN=localvar studio" sign.cer&lt;/P&gt;
&lt;P&gt;2. 把x.509证书转换为Software Publisher Certificate&lt;BR&gt;cert2spc sign.cer sign.spc&lt;/P&gt;
&lt;P&gt;3. 把pvk转换为pfx, 例子中的123是私钥密码&lt;BR&gt;pvk2pfx -pvk sign.pvk -pi 123 -spc sign.spc -pfx sign.pfx&lt;/P&gt;
&lt;P&gt;4. 签名, 稍微调整一下，就能写在post build event里了，123是密码&lt;BR&gt;signtool sign /f sign.pfx /p 123 test.exe&lt;/P&gt;
&lt;P&gt;上面的例子只是演示签名过程，由于证书是本机做出来的，所以签了名也没用，用户那看到的仍然是&amp;#8220;未知发行商&amp;#8221;。向证书颁发机构申请真正的证书时，能直接得到.spc和.pvk文件，所以就不用执行前两步了。&lt;/P&gt;
&lt;P&gt;PS: 证书颁发机构真是坐地收钱呀，几秒钟生成个证书，每年就收好几千。&lt;/P&gt;&lt;img src ="http://blog.vckbase.com/localvar/aggbug/35679.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>局部变量</dc:creator><title>_tfopen指定文件编码后程序崩溃</title><link>http://blog.vckbase.com/localvar/archive/2008/11/03/35543.html</link><pubDate>Mon, 03 Nov 2008 04:58:00 GMT</pubDate><guid>http://blog.vckbase.com/localvar/archive/2008/11/03/35543.html</guid><wfw:comment>http://blog.vckbase.com/localvar/comments/35543.html</wfw:comment><comments>http://blog.vckbase.com/localvar/archive/2008/11/03/35543.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://blog.vckbase.com/localvar/comments/commentRss/35543.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/localvar/services/trackbacks/35543.html</trackback:ping><description>vs05和08的crt增加了一点功能, 使用fopen(_wfopen)时可以指定文件的编码, 但我发现这个功能好像有很多bug, 会导致程序崩溃。&lt;BR&gt;我是使用下面的形式打开文件的:&lt;BR&gt;TCHAR buf[1024];&lt;BR&gt;FILE* fp = _tfopen( _T(&amp;#8220;a.txt&amp;#8221;) , _T(&amp;#8221;rt,ccs=UNICODE&amp;#8221;) );&lt;BR&gt;_fgetts( buf, _countof(buf), fp );&lt;BR&gt;按msdn的说法，这时fopen会根据文件的bom自动判断文件的编码, 并保证buf中字符的编码总是我希望的那一种。&lt;BR&gt;可是这个程序在使用mbcs并打开unicode编码的文件时会崩溃, 考虑到我的程序只发布unicode版本, 所以忍了，啥也不说。&lt;BR&gt;但这两天发现, UNICODE版本在fgets时也会崩溃, 方法是新建一个excel文件然后重命名为a.txt。&lt;BR&gt;&lt;BR&gt;我仔细读了两天msdn，并测试了各种形式，感觉不像是我的错误。&lt;BR&gt;在网上没找到类似的描述, 所以记下来，也许有人会碰到同样的问题。&lt;img src ="http://blog.vckbase.com/localvar/aggbug/35543.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>局部变量</dc:creator><title>多线程和函数里的静态变量</title><link>http://blog.vckbase.com/localvar/archive/2008/05/29/33945.html</link><pubDate>Thu, 29 May 2008 01:33:00 GMT</pubDate><guid>http://blog.vckbase.com/localvar/archive/2008/05/29/33945.html</guid><wfw:comment>http://blog.vckbase.com/localvar/comments/33945.html</wfw:comment><comments>http://blog.vckbase.com/localvar/archive/2008/05/29/33945.html#Feedback</comments><slash:comments>19</slash:comments><wfw:commentRss>http://blog.vckbase.com/localvar/comments/commentRss/33945.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/localvar/services/trackbacks/33945.html</trackback:ping><description>&lt;DIV&gt;试试下面这段代码的输出是什么?&lt;/DIV&gt;
&lt;TABLE style="BORDER-COLLAPSE: collapse" borderColor=#999999 cellSpacing=0 cellPadding=0 width="75%" bgColor=#f1f1f1 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;P style="MARGIN: 5px; LINE-HEIGHT: 150%"&gt;&lt;CODE&gt;&lt;SPAN style="COLOR: #000000"&gt;&lt;SPAN style="COLOR: #0000cc"&gt;#&lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;include&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000cc"&gt;&amp;lt;&lt;/SPAN&gt;stdio&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;h&lt;SPAN style="COLOR: #0000cc"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;#&lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;include&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000cc"&gt;&amp;lt;&lt;/SPAN&gt;process&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;h&lt;SPAN style="COLOR: #0000cc"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;#&lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;include&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000cc"&gt;&amp;lt;&lt;/SPAN&gt;windows&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;h&lt;SPAN style="COLOR: #0000cc"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;class&lt;/SPAN&gt; foo&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;{&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;:&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;foo&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000cc"&gt;{&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #ff0000"&gt;printf&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff00ff"&gt;"before sleep\n"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #ff0000"&gt;Sleep&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt; 1000 &lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #ff0000"&gt;printf&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff00ff"&gt;"after sleep\n"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000cc"&gt;}&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;test&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000cc"&gt;{&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #ff0000"&gt;printf&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff00ff"&gt;"in test\n"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000cc"&gt;}&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;}&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&lt;BR&gt;foo&lt;SPAN style="COLOR: #0000cc"&gt;*&lt;/SPAN&gt; bar&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;{&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; foo a&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;return&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000cc"&gt;&amp;amp;&lt;/SPAN&gt;a&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;}&lt;/SPAN&gt;&lt;BR&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;unsigned&lt;/SPAN&gt; __stdcall thread&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;*&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;{&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;foo&lt;SPAN style="COLOR: #0000cc"&gt;*&lt;/SPAN&gt; p &lt;SPAN style="COLOR: #0000cc"&gt;=&lt;/SPAN&gt; bar&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;p&lt;SPAN style="COLOR: #0000cc"&gt;-&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;test&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;return&lt;/SPAN&gt; 0&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;}&lt;/SPAN&gt;&lt;BR&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt; _cdecl main&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt; argc&lt;SPAN style="COLOR: #0000cc"&gt;,&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;char&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;*&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;*&lt;/SPAN&gt; argv &lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;{&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;for&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt; i &lt;SPAN style="COLOR: #0000cc"&gt;=&lt;/SPAN&gt; 0&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt; i &lt;SPAN style="COLOR: #0000cc"&gt;&amp;lt;&lt;/SPAN&gt; 10&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000cc"&gt;+&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;+&lt;/SPAN&gt;i &lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000cc"&gt;{&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #ff0000"&gt;uintptr_t&lt;/SPAN&gt; t &lt;SPAN style="COLOR: #0000cc"&gt;=&lt;/SPAN&gt; _beginthreadex&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;NULL&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;,&lt;/SPAN&gt; 0&lt;SPAN style="COLOR: #0000cc"&gt;,&lt;/SPAN&gt; thread&lt;SPAN style="COLOR: #0000cc"&gt;,&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;NULL&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;,&lt;/SPAN&gt; 0&lt;SPAN style="COLOR: #0000cc"&gt;,&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;NULL&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CloseHandle&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt;HANDLE&lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;t &lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000cc"&gt;}&lt;/SPAN&gt;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #ff0000"&gt;Sleep&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt; 5000 &lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;return&lt;/SPAN&gt; 0&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;}&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/CODE&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;BR&gt;不知道C/C++标准有什么规定没有, 但粗看起来好像是编译器的问题呀。我用的是vc8，谁帮忙测测别的编译器。&lt;BR&gt;根据星星的建议，把输出贴出来，如下：&lt;BR&gt;before sleep&lt;BR&gt;in test&lt;BR&gt;in test&lt;BR&gt;in test&lt;BR&gt;in test&lt;BR&gt;in test&lt;BR&gt;in test&lt;BR&gt;in test&lt;BR&gt;in test&lt;BR&gt;in test&lt;BR&gt;after sleep&lt;BR&gt;in test&lt;BR&gt;这里的问题是至少有10个中的9个线程没有等对象初始化完成，就已经调用对象的方法了，这肯定是不对的。我大概看了一下反汇编的结果，实际上还可能出现构造函数被调用多次的情况。&lt;BR&gt;要解决这个问题，在编译器的层次上要容易一点。如果是在用户程序的层次上，则麻烦的多，因为这类方法都会涉及到另一个静态变量的初始化。&lt;img src ="http://blog.vckbase.com/localvar/aggbug/33945.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>局部变量</dc:creator><title>使用SVN实现版本号自增</title><link>http://blog.vckbase.com/localvar/archive/2008/05/20/33718.html</link><pubDate>Tue, 20 May 2008 01:12:00 GMT</pubDate><guid>http://blog.vckbase.com/localvar/archive/2008/05/20/33718.html</guid><wfw:comment>http://blog.vckbase.com/localvar/comments/33718.html</wfw:comment><comments>http://blog.vckbase.com/localvar/archive/2008/05/20/33718.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://blog.vckbase.com/localvar/comments/commentRss/33718.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/localvar/services/trackbacks/33718.html</trackback:ping><description>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在《介绍一下SVN》一文中，我提到了自动递增版本号的功能，现在就来具体说明一下实现方法。虽然标题中说的是&amp;#8220;使用SVN&amp;#8221;，但我们实际用的是SVN的客户端工具TortoiseSVN中的SubWCRev程序。另外文中的例子也使用了Visual Studio的SVN插件VisualSVN，它并非必须，用了方便一些，不用也行。我平时主要使用C/C++语言，但考虑C#有更大的用户群，我的示例项目也采用了C#。
&lt;H3&gt;&lt;/H3&gt;
&lt;H4&gt;1.&amp;nbsp;生成一个名为autover的项目&lt;/H4&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;注意项目的Properties文件夹下有一个名为AssemblyInfo.cs的文件，autover程序的版本号就写在它里面。&lt;/P&gt;&lt;IMG src="/images/vckbase_com/localvar/1234/o_image001.jpg"&gt; 
&lt;H4&gt;2.&amp;nbsp;创建模板文件&lt;/H4&gt;
&lt;P&gt;在windows的资源管理器中进入Properties文件夹，把AssemblyInfo.cs文件复制一份，命名为AssemblyInfo.template.cs，并把它加入到项目中来。&lt;/P&gt;&lt;IMG src="/images/vckbase_com/localvar/1234/o_image002.jpg"&gt; 
&lt;H4&gt;3.&amp;nbsp;修改AssemblyInfo.template.cs的属性&lt;/H4&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AssemblyInfo.template.cs文件是用来自动生成版本号的模板文件，它不应该被编译，所以我们要把它的Build Action改成None，如下图所示：&lt;/P&gt;&lt;IMG src="/images/vckbase_com/localvar/1234/o_image003.jpg"&gt; 
&lt;H4&gt;4.&amp;nbsp;修改AssemblyInfo.template.cs的内容&lt;/H4&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在这个文件中，你能找到如下两行代码： &lt;BR&gt;&lt;FONT color=#0000ff&gt;[assembly: AssemblyVersion( "1.0.0.0" )] &lt;BR&gt;[assembly: AssemblyFileVersion( "1.0.0.0" )] &lt;BR&gt;&lt;/FONT&gt;其中的&amp;#8220;1.0.0.0&amp;#8221;就是程序的版本号，它使用的是&amp;#8220;主版本号.次版本号.内部版本号.修订号&amp;#8221;的形式。前三个改成你自己需要的数字，最后一个改成&amp;#8220;$WCREV$&amp;#8221;，改完之后应该是类似下面的样子： &lt;BR&gt;&lt;FONT color=#0000ff&gt;[assembly: AssemblyVersion( "1.0.0.$WCREV$" )] &lt;BR&gt;[assembly: AssemblyFileVersion( "1.0.0.$WCREV$" )]&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在这个文件的最后，你还应该加上下面两段代码，它们可以检测出有本地修改（修改了但没有提交）的代码和有混合版本的代码。 &lt;BR&gt;&lt;FONT color=#0000ff&gt;#if $WCMIXED?true:false$ &lt;BR&gt;#if DEBUG &lt;BR&gt;#warning mixed update revisions founded &lt;BR&gt;#else &lt;BR&gt;#error mixed update revisions founded &lt;BR&gt;#endif &lt;BR&gt;#endif &lt;BR&gt;&lt;BR&gt;#if $WCMODS?true:false$ &lt;BR&gt;#if DEBUG &lt;BR&gt;#warning local modification founded &lt;BR&gt;#else &lt;BR&gt;#error local modification founded &lt;BR&gt;#endif &lt;BR&gt;#endif&lt;/FONT&gt;&lt;/P&gt;
&lt;H4&gt;5.&amp;nbsp;修改项目属性&lt;/H4&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在项目属性的Build Event页的Pre-build event command line中输入： &lt;BR&gt;&lt;FONT color=#0000ff&gt;"%ProgramFiles%\TortoiseSVN\bin\SubWCRev.exe" $(SolutionDir) $(ProjectDir)Properties\AssemblyInfo.template.cs $(ProjectDir)Properties\AssemblyInfo.cs -f &lt;BR&gt;&lt;/FONT&gt;注意，这里我们必须保证TortoiseSVN安装到了默认路径上。在多人参加的项目中这应该是强制性的要求，否则，大家安装的路径都不一样，甲机器上能用的配置，到了乙机器上可能就不行了。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;然后，你可能还需要将Publish页中的Automatically increment revision with each publish选项关掉（我不确定这步是否必须）。C#可以自己递增版本号，但它生成的版本号和代码库中的代码没有对应关系，我个人觉得意义不大。并且它还可能会把我们的版本自增机制搞乱。所以应该关掉。&lt;/P&gt;
&lt;H4&gt;6.&amp;nbsp;把项目加入版本库&lt;/H4&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;使用VisualSVN的Add solution to Subversion命令把项目加入SVN，但不要提交。&lt;/P&gt;
&lt;H4&gt;7.&amp;nbsp;从SVN中排除AssemblyInfo.cs文件&lt;/H4&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;每次编译时，这个文件都会基于AssemblyInfo.template.cs重新生成，所以没必要加入版本库。这步做完之后就可以提交整个项目了。&lt;/P&gt;&lt;IMG src="/images/vckbase_com/localvar/1234/o_image004.jpg"&gt; 
&lt;H4&gt;8.&amp;nbsp;编译&lt;/H4&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;编译完成后，看一下生成的autover.exe文件的版本信息，本例中是1.0.0.1。随便改点什么，提交，重新编译，你会发现它自动变成了1.0.0.2，也就是程序的修订号总是与生成它的代码的修订号一致。这样，当程序出问题后，我们通过这个数字就能轻松得到生成它的那一版代码了。&lt;/P&gt;&lt;IMG src="/images/vckbase_com/localvar/1234/o_image005.jpg"&gt; 
&lt;H4&gt;9.&amp;nbsp;其它问题&lt;/H4&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;第8步中大家做完修改后再编译时可能会看到警告或错误信息，说代码有本地修改或混合版本。这就是第4步中，在AssemblyInfo.template.cs文件最后加的两段代码的作用，它们检测代码是否都已经提交了并且版本是否一致，一旦发现问题就会在调试版中生成警告信息，在发布版中生成错误信息。使用这种方法，我们可以基本消除发布的程序的版本和代码的版本出现不一致的可能性。去掉这两个错误或警告的方法也很简单，把代码整体提交或更新一下就行了。&lt;/P&gt;&lt;img src ="http://blog.vckbase.com/localvar/aggbug/33718.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>局部变量</dc:creator><title>再记自己的两个常识性错误</title><link>http://blog.vckbase.com/localvar/archive/2008/01/08/31689.html</link><pubDate>Tue, 08 Jan 2008 03:58:00 GMT</pubDate><guid>http://blog.vckbase.com/localvar/archive/2008/01/08/31689.html</guid><wfw:comment>http://blog.vckbase.com/localvar/comments/31689.html</wfw:comment><comments>http://blog.vckbase.com/localvar/archive/2008/01/08/31689.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://blog.vckbase.com/localvar/comments/commentRss/31689.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/localvar/services/trackbacks/31689.html</trackback:ping><description>&lt;P&gt;1. WSAStartup只要每个进程调用一次就行了&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 不知为什么, 几年以来，我一直认为要为每个使用网络的线程调一次. 直到今天才发现弄错了, 按说我一直是仔细阅读msdn的, 唉! 不过为每个线程调一次只是多余的, 并不是错误的, 也许这就是我一直没有注意到它的原因吧.&lt;BR&gt;2. do while循环中的continue会跳到哪里&lt;/P&gt;
&lt;DIV style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid"&gt;
&lt;DIV&gt;&lt;SPAN style="COLOR: #0000ff"&gt;do&lt;/SPAN&gt;&lt;SPAN style="COLOR: #000000"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN id=Codehighlighter1_3_42_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"&gt;&lt;/SPAN&gt;&lt;SPAN id=Codehighlighter1_3_42_Open_Text&gt;&lt;SPAN style="COLOR: #000000"&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;//&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;&amp;nbsp;①&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;i&lt;/SPAN&gt;&lt;SPAN style="COLOR: #000000"&gt;++&lt;/SPAN&gt;&lt;SPAN style="COLOR: #000000"&gt;;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;continue&lt;/SPAN&gt;&lt;SPAN style="COLOR: #000000"&gt;;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;//&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;&amp;nbsp;②&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #000000"&gt;}&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #000000"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;while&lt;/SPAN&gt;&lt;SPAN style="COLOR: #000000"&gt;(&amp;nbsp;i&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #000000"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #000000"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #000000"&gt;10&lt;/SPAN&gt;&lt;SPAN style="COLOR: #000000"&gt;&amp;nbsp;);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 一直认为是①, 今天正在写的程序出错了才发现是②. 老天保佑以前的程序不出错吧&lt;IMG height=20 src="/Emoticons/QQ/02.gif" width=20 border=0&gt;. 这个错误一直没发现的原因有两点，一是我用do while循环比较少, 里面有continue的更少; 二是自己偷懒了, 想当然了, 其实以前怀疑过它的结果的, 但觉得①更符合逻辑就没有深究.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 犯了错误总是比较郁闷的, 不过能在一个上午认识到这样两个错误，也算收获不小了。&lt;/P&gt;&lt;img src ="http://blog.vckbase.com/localvar/aggbug/31689.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>局部变量</dc:creator><title>Windows下配置SVN 1.4.5 + APACHE 2.2.6使用域认证</title><link>http://blog.vckbase.com/localvar/archive/2007/12/20/31427.html</link><pubDate>Thu, 20 Dec 2007 06:28:00 GMT</pubDate><guid>http://blog.vckbase.com/localvar/archive/2007/12/20/31427.html</guid><wfw:comment>http://blog.vckbase.com/localvar/comments/31427.html</wfw:comment><comments>http://blog.vckbase.com/localvar/archive/2007/12/20/31427.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://blog.vckbase.com/localvar/comments/commentRss/31427.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/localvar/services/trackbacks/31427.html</trackback:ping><description>&lt;DIV&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 其实在网上搜索这个主题，已经有很多文章了，而且Subversion和TortoiseSVN的文档上也有相关介绍。但在我自己配置的过程中，发现它们好像都不完全对。所以我觉得有必要把自己摸索的过程写出来，供大家参考。不过已经有那么多&amp;#8220;前车之鉴&amp;#8221;了，我的方法是否真的有用，只能靠老天保佑了。&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;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时，我们应该到&lt;A href="http://subversion.tigris.org/servlets/ProjectDocumentList?expandFolder=91&amp;amp;folderID=9246" target=_blank&gt;这里&lt;/A&gt;，点击左侧的文件夹&lt;A href="http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=8100&amp;amp;expandFolder=8100&amp;amp;folderID=9246" target=_blank&gt;Windows Apache 2.2.x&lt;/A&gt;（等以后有了新版的apache，可能就是其它对应的文件夹了），然后在右侧的文件列表中下载对应得svn（我下载的是&lt;A href="http://subversion.tigris.org/downloads/1.4.5-win32/apache-2.2/svn-win32-1.4.5.zip" target=_blank&gt;svn-win32-1.4.5.zip&lt;/A&gt;）。mod_auth_sspi我们也下载针对2.2.x版apache的那个就可以了。&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 以下是我的安装配置过程，它是针对apache2.2.6和svn1.4.5的，如果你用的是其它版本，可能一些细节上会有所不同。&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;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也拷贝到那去。&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 最后是修改apache的配置文件httpd.conf，经过我的试验，最后确定使用下面配置文件就行了（其中背景标红的内容你可能需要根据你的实际情况进行修改）。&lt;/DIV&gt;
&lt;TABLE style="BORDER-COLLAPSE: collapse" borderColor=#999999 cellSpacing=0 cellPadding=0 width="75%" bgColor=#f1f1f1 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;P style="MARGIN: 5px; LINE-HEIGHT: 150%"&gt;&lt;CODE&gt;&lt;SPAN style="COLOR: #000000"&gt;&lt;SPAN style="COLOR: #0000ff"&gt;ThreadsPerChild&lt;/SPAN&gt; 250&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;MaxRequestsPerChild&lt;/SPAN&gt; 0&lt;BR&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;ServerRoot&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff00ff"&gt;"&lt;FONT style="BACKGROUND-COLOR: #ff0000" color=#000000&gt;C:/Program Files/Apache Software Foundation/Apache2.2&lt;/FONT&gt;"&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;ServerName&lt;/SPAN&gt; &lt;FONT style="BACKGROUND-COLOR: #ff0000"&gt;svnserver.mydomain.net&lt;SPAN style="COLOR: #0000cc"&gt;:&lt;/SPAN&gt;8080&lt;/FONT&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;ServerSignature&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;Off&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;ServerTokens&lt;/SPAN&gt; Prod&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;DocumentRoot&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff00ff"&gt;"htdocs"&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;Listen&lt;/SPAN&gt; &lt;FONT style="BACKGROUND-COLOR: #ff0000"&gt;8080&lt;/FONT&gt;&lt;BR&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;LoadModule&lt;/SPAN&gt; sspi_auth_module modules/mod_auth_sspi.so&lt;BR&gt;#&lt;SPAN style="COLOR: #0000ff"&gt;LoadModule&lt;/SPAN&gt; auth_basic_module modules/mod_auth_basic.so&lt;BR&gt;#&lt;SPAN style="COLOR: #0000ff"&gt;LoadModule&lt;/SPAN&gt; auth_digest_module modules/mod_auth_digest.so&lt;BR&gt;#&lt;SPAN style="COLOR: #0000ff"&gt;LoadModule&lt;/SPAN&gt; authn_file_module modules/mod_authn_file.so&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;LoadModule&lt;/SPAN&gt; authz_svn_module modules/mod_authz_svn.so&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;LoadModule&lt;/SPAN&gt; dir_module modules/mod_dir.so&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;LoadModule&lt;/SPAN&gt; deflate_module modules/mod_deflate.so&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;LoadModule&lt;/SPAN&gt; mime_module modules/mod_mime.so&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;LoadModule&lt;/SPAN&gt; setenvif_module modules/mod_setenvif.so&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;LoadModule&lt;/SPAN&gt; dav_module modules/mod_dav.so&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;LoadModule&lt;/SPAN&gt; dav_svn_module modules/mod_dav_svn.so&lt;BR&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;Directory&lt;/SPAN&gt; /&lt;SPAN style="COLOR: #0000cc"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;Options&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;FollowSymLinks&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;AllowOverride&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;None&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;Directory&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;IfModule&lt;/SPAN&gt; dir_module&lt;SPAN style="COLOR: #0000cc"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;DirectoryIndex&lt;/SPAN&gt; index.html&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;IfModule&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;ErrorLog&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff00ff"&gt;"&lt;FONT style="BACKGROUND-COLOR: #ff0000" color=#000000&gt;e:/svn/server.log&lt;/FONT&gt;"&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;LogLevel&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;error&lt;/SPAN&gt;&lt;BR&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;DefaultType&lt;/SPAN&gt; text/plain&lt;BR&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;IfModule&lt;/SPAN&gt; mime_module&lt;SPAN style="COLOR: #0000cc"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;TypesConfig&lt;/SPAN&gt; conf/mime.types&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;AddType&lt;/SPAN&gt; application/x-compress .Z&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;AddType&lt;/SPAN&gt; application/x-gzip .gz .tgz&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;AddType&lt;/SPAN&gt; application/x-x509-&lt;SPAN style="COLOR: #ff0000"&gt;ca&lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;-&lt;/SPAN&gt;cert .crt&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;AddType&lt;/SPAN&gt; application/x-pkcs7-crl .crl&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;IfModule&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;&lt;FONT color=#000000&gt;# 注意&amp;#8220;/svn/&amp;#8221;中最后的斜杠是必须的, 否则列不出版本库列表&lt;BR&gt;# 访问时的url也要带着它, 想要去掉它可搜索RedirectMatch&lt;/FONT&gt;&lt;BR&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;Location&lt;/SPAN&gt; &lt;FONT style="BACKGROUND-COLOR: #ff0000"&gt;/svn/&lt;/FONT&gt;&lt;SPAN style="COLOR: #0000cc"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# configure SVN&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;DAV&lt;/SPAN&gt; svn&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SVNListParentPath &lt;SPAN style="COLOR: #ff0000"&gt;on&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 版本库的根目录&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SVNParentPath &lt;FONT style="BACKGROUND-COLOR: #ff0000"&gt;e&lt;SPAN style="COLOR: #0000cc"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;/&lt;/SPAN&gt;svn&lt;/FONT&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 权限控制文件&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AuthzSVNAccessFile &lt;FONT style="BACKGROUND-COLOR: #ff0000"&gt;e&lt;SPAN style="COLOR: #0000cc"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;/&lt;/SPAN&gt;svn/authz&lt;/FONT&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 认证时的提示信息(中文不好使)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;AuthName&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff00ff"&gt;"&lt;FONT style="BACKGROUND-COLOR: #ff0000" color=#000000&gt;My Subversion&lt;/FONT&gt;"&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 使用域认证&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;AuthType&lt;/SPAN&gt; SSPI&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SSPIAuth &lt;SPAN style="COLOR: #ff0000"&gt;On&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SSPIAuthoritative &lt;SPAN style="COLOR: #ff0000"&gt;On&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 指定使用那个域&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SSPIDomain &lt;FONT style="BACKGROUND-COLOR: #ff0000"&gt;mydomain.net&lt;/FONT&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 是否省略掉用户id的域名部分(好像只是影响svn的一些日志记录)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SSPIOmitDomain &lt;SPAN style="COLOR: #ff0000"&gt;On&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 是否允许非IE客户端(必须打开)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SSPIOfferBasic &lt;SPAN style="COLOR: #ff0000"&gt;On&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 基本认证(非域认证方式)具有更高的优先级?&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SSPIBasicPreferred &lt;SPAN style="COLOR: #ff0000"&gt;Off&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 用户名大小写&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SSPIUsernameCase lower&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# 用户必须通过认证&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;Require&lt;/SPAN&gt; valid-&lt;SPAN style="COLOR: #0000ff"&gt;user&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;Location&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/CODE&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 最后如果大家觉得手工编辑那个权限控制文件（authz）很麻烦的话，也有一个取巧的办法，就是使用visualsvn server，虽然它目前还不支持域认证，但是我们可以借用它的权限管理界面。操作如下（假设版本库的根目录是e:\svn，并且权限控制文件的名字这时必须用authz）：&lt;BR&gt;1）&amp;nbsp;按前面的操作安装好apache和svn，但不要启动apache&lt;BR&gt;2）&amp;nbsp;把e:\svn改名为e:\svn1&lt;BR&gt;3）&amp;nbsp;&lt;A href="http://www.visualsvn.com/server" target=_blank&gt;下载&lt;/A&gt;并安装visualsvn server，安装时指定版本库根目录为e:\svn&lt;BR&gt;4）&amp;nbsp;停掉并禁用visualsvn server的服务（VisualSVNServer），删除e:\svn&lt;BR&gt;5）&amp;nbsp;把e:\svn1的名字改回e:\svn&lt;BR&gt;6）&amp;nbsp;启动apache&lt;BR&gt;7）&amp;nbsp;启动visualsvn server的管理界面，把要使用这个版本库的所有人的域帐号都添加到它的用户列表中去（密码不会被实际使用，随便设或留空都行）。&lt;BR&gt;8）&amp;nbsp;万事ok了，设置权限吧！&lt;BR&gt;
&lt;DIV&gt;&lt;BR&gt;ps: 2008-05-23&lt;BR&gt;tortoisesvn(1.4.8版)文档中关于使用多认证源的描述中有一个错误，其中的&lt;FONT color=#ff0000&gt;AuthAthoritative&lt;/FONT&gt;&lt;FONT color=#000000&gt;和&lt;/FONT&gt;&lt;FONT color=#ff0000&gt;AuthAuthoritative&lt;FONT color=#000000&gt;都应该改成&lt;/FONT&gt;&lt;FONT color=#ff0000&gt;AuthBasicAuthoritative&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT color=#000000&gt;。另外，多认证源还要求域用户登录时必须用&amp;#8220;domain\user&amp;#8221;的形式，只输user部分就会用其他认证方式。所以，如果你按我前面的描述用了visual svn server，增加多认证源后，域用户的密码就千万不要留空了，因为那样不用密码就能登录了。&lt;BR&gt;&lt;/FONT&gt;&lt;/DIV&gt;&lt;img src ="http://blog.vckbase.com/localvar/aggbug/31427.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>局部变量</dc:creator><title>介绍一下Subversion</title><link>http://blog.vckbase.com/localvar/archive/2007/12/18/31344.html</link><pubDate>Tue, 18 Dec 2007 02:42:00 GMT</pubDate><guid>http://blog.vckbase.com/localvar/archive/2007/12/18/31344.html</guid><wfw:comment>http://blog.vckbase.com/localvar/comments/31344.html</wfw:comment><comments>http://blog.vckbase.com/localvar/archive/2007/12/18/31344.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://blog.vckbase.com/localvar/comments/commentRss/31344.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/localvar/services/trackbacks/31344.html</trackback:ping><description>&lt;DIV align=left&gt;本来是发在公司内刊上的，现在拿来这里凑个数。&lt;/DIV&gt;
&lt;DIV align=left&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV align=left&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 前一段时间，公司讨论统一配置管理工具时，我推荐了svn（subversion）。照理说，在公司已经使用了vss、cvs和ClearCase三种工具的情况下，再提一种基本没人用过的新工具不是什么明智的选择。但我确实觉得svn的优点很突出，值得一荐。下面我就对svn进行一下简单介绍，让各位同事对其有一个初步的了解。&lt;/DIV&gt;
&lt;H4&gt;1.&amp;nbsp;与其他工具的对比&lt;/H4&gt;
&lt;DIV&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; vss是我用的最多的配置工具，所以我相信每个用过vss的人都会对它的离线操作功能头疼不已。虽然它允许在与服务器断开的情况下修改文件，但重新连接后必须非常小心的处理每个文件，一旦出错，就会造成不小的麻烦。svn则没有这个问题。二者更详细的区别我会在下一节说明，这里就不多啰嗦了。&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; svn相对cvs是有明显优势的，因为svn的设计目标之一就是&amp;#8220;一个更好的cvs&amp;#8221;。而且，从众多开源项目的反映看，它也确实达到了这个目标：06年，最大的开源网站SourceForge开始支持svn；KDE和GNOME的开发团队也已经换用svn；如果大家多注意一下的话，还会发现更多著名的开源项目使用了svn。&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ClearCase我没有实际使用过，按说应该无权评价。不过，我没有用过它的原因是因为它太难用了，曾经学过几天，但后来觉得太过复杂，就转向vss了。相比之下，svn是比较简单的，我大概花了一两天的时间就可以完成基本操作了，用的比较熟练也不过两周。另外就是ClearCase要钱，而svn是免费的。&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下表是这几种工具的对比，列出的功能都是我比较关心的。更详细的比较，大家可以看看&lt;A href="http://better-scm.berlios.de/comparison/"&gt;http://better-scm.berlios.de/comparison/&lt;/A&gt;。&lt;/DIV&gt;
&lt;DIV&gt;
&lt;TABLE cellSpacing=1 cellPadding=1 width="75%" border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;P align=center&gt;&lt;STRONG&gt;项目&lt;/STRONG&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;&lt;STRONG&gt;Vss&lt;/STRONG&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;&lt;STRONG&gt;Clearcase&lt;/STRONG&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;&lt;STRONG&gt;Cvs&lt;/STRONG&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;&lt;STRONG&gt;svn&lt;/STRONG&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;文件/目录的重命名或移动&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是?&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;否&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;P align=left&gt;&amp;nbsp;原子提交&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;否&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;否&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;P align=left&gt;&amp;nbsp;变更集&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;否&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;可间接实现&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;否&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;P align=left&gt;&amp;nbsp;中文支持&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;未知&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;差&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;P align=left&gt;&amp;nbsp;visual studio集成&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;P align=left&gt;&amp;nbsp;eclipse集成&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;未知&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;未知&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;P align=left&gt;&amp;nbsp;http访问&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;8.0支持&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;差&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;P align=left&gt;&amp;nbsp;离线操作&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;差&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;未知&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;P align=left&gt;&amp;nbsp;权限管理&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;较差&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;是&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;P align=left&gt;&amp;nbsp;易用性&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;简单&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;复杂&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;较简单&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;较简单&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;P align=left&gt;&amp;nbsp;授权&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;商业&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;商业&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;GPL&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;
&lt;TD&gt;
&lt;P align=center&gt;Apache/BSD&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;
&lt;H4&gt;2.&amp;nbsp;svn能解决哪些问题&lt;/H4&gt;
&lt;DIV&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 一直以来，XXXX项目都是使用vss作为配置管理工具的，但应用过程中我也越来越感觉到vss满足不了项目的需要，所以决定在项目组内试用svn，并在合适的时机完全转换到svn。具体说来，svn可以解决以下几个（包括但不限于&lt;IMG height=20 src="/Emoticons/QQ/smile.gif" width=20 border=0&gt;）问题。&lt;/DIV&gt;
&lt;H5&gt;2.1.&amp;nbsp;获取某个以前的版本&lt;/H5&gt;
&lt;DIV&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 我想获得三天前签入的某个版本怎么办？在vss中，如果没有打标签，那可能就只有一个文件一个文件的去找了。规定每次签入都打个标签或许是个解决办法，不过这项规定能否很好的执行就是另一个问题了。在svn中，每次签入（准确地说应该是&amp;#8220;提交&amp;#8221;）都会为整个代码库生成一个确定的版本，所以能够轻松完成此任务。&lt;/DIV&gt;
&lt;H5&gt;2.2.&amp;nbsp;自动递增版本号&lt;/H5&gt;
&lt;DIV&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; XXXX发布后，现场经常会反馈回来一些问题。但我发现这些问题中有不少是由于程序版本不匹配或没有用最新的程序造成的。所以我就想在编译过程中实现一个自增版本号的功能，每次修改后，能自动生成一个版本号，并且能把它显示在程序的关于对话框等位置，这样工程人员就能直接把这些原因造成的问题排除掉了。让我失望的是vss做不到这一点，虽然它有&amp;#8220;关键字扩展（keyword expansion）&amp;#8221;功能，但实现不了我的需求。而如果要求每次编译前手工修改版本号，就是另外一个能否切实执行的问题，我对这类问题的总是很悲观的。&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 前面已经说过，在svn中，每次签入（提交）都会为整个代码库生产一个版本。生成它的同时，svn还会为其指定一个递增的修订号，利用这个修订号和一个配套的工具（SubWCRev)，就可以做到自动生成版本号了。&lt;/DIV&gt;
&lt;H5&gt;2.3.&amp;nbsp;变更集&lt;/H5&gt;
&lt;DIV&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 作为项目经理或设计人员，大家可能还会经常希望知道某个开发人员的某次签入到底修改了哪些内容，这一点在vss中也是做不到的。而在svn中，只要比较签入前的版本和签入后的版本就行了。实际上，在svn中，你可以比较任意两个版本之间的区别，甚至能追查到一个文件中每行代码的责任人。&lt;/DIV&gt;
&lt;H5&gt;2.4.&amp;nbsp;离线操作&lt;/H5&gt;
&lt;DIV&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这个在前面已经说过了，再提一次是想强调一下我有多希望配置管理工具支持此功能。&lt;/DIV&gt;
&lt;H3&gt;3.&amp;nbsp;相关工具和网站&lt;/H3&gt;
&lt;DIV&gt;&lt;STRONG&gt;TortoiseSvn：&lt;/STRONG&gt;是windows下功能最强、最实用的svn客户端。它与资源管理器的右键菜单集成，可以管理包括源代码在内的任何文件。它的&amp;#8220;图标叠加（Icon Overlay）&amp;#8221;功能，可以让我们从文件和文件夹的图标中直观的看出它们的状态，如是否被修改等。另外，前面提到的SubWCRev就是它的一部分。&lt;BR&gt;&lt;STRONG&gt;AnkhSvn：&lt;/STRONG&gt;一个visual studio的svn插件，支持svn的大部分功能，并且比较好用。&lt;BR&gt;&lt;STRONG&gt;VisualSvn：&lt;/STRONG&gt;也是一个visual studio的svn插件，应该比AnkhSvn好一些，不过它是商业软件。&lt;/DIV&gt;
&lt;DIV&gt;&lt;STRONG&gt;VisualSvn Server：&lt;/STRONG&gt;windows下svn+apache的组合，提供了一个mmc的管理界面，喜欢gui界面的人的福音。而且，虽然它和VisualSvn是同一家公司的产品，但它是免费的。&lt;BR&gt;&lt;STRONG&gt;Subclipse：&lt;/STRONG&gt;eclipse的svn插件，也已经很成熟，据说使用风格和eclipse自带的cvs插件非常像。&lt;BR&gt;&lt;STRONG&gt;p4merge：&lt;/STRONG&gt;这是一个文件对比/合并工具，TortoiseSvn自带的文件比较工具还比较好用，但合并工具就差点了，起码没有vss的好用。能找到的工具大多只支持双视图合并。p4merge则能支持三视图甚至四视图，用起来方便很多。开发这个工具的公司也是做配置管理软件的，不过这个公司比较好，只对它的服务器端收费，其他工具都可以免费用。&lt;BR&gt;&lt;A href="http://www.tigris.org/"&gt;&lt;STRONG&gt;http://www.tigris.org/&lt;/STRONG&gt;&lt;/A&gt;&lt;STRONG&gt;：&lt;/STRONG&gt;这是subversion、TortoiseSvn、AnkhSvn以及其它众多开源软件开发管理工具的官方站点。&lt;BR&gt;&lt;A href="http://www.subversion.org.cn/"&gt;&lt;STRONG&gt;http://www.subversion.org.cn/&lt;/STRONG&gt;&lt;/A&gt;&lt;STRONG&gt;：&lt;/STRONG&gt;svn中文网站。&lt;BR&gt;&lt;A href="http://www.iusesvn.com/"&gt;&lt;STRONG&gt;http://www.iusesvn.com/&lt;/STRONG&gt;&lt;/A&gt;&lt;STRONG&gt;：&lt;/STRONG&gt;也是一个svn的中文网站，内容和上一个有很多是重复的。&lt;BR&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;/DIV&gt;&lt;img src ="http://blog.vckbase.com/localvar/aggbug/31344.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>局部变量</dc:creator><title>锁？不锁？如何锁？</title><link>http://blog.vckbase.com/localvar/archive/2007/10/15/29995.html</link><pubDate>Mon, 15 Oct 2007 01:46:00 GMT</pubDate><guid>http://blog.vckbase.com/localvar/archive/2007/10/15/29995.html</guid><wfw:comment>http://blog.vckbase.com/localvar/comments/29995.html</wfw:comment><comments>http://blog.vckbase.com/localvar/archive/2007/10/15/29995.html#Feedback</comments><slash:comments>13</slash:comments><wfw:commentRss>http://blog.vckbase.com/localvar/comments/commentRss/29995.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/localvar/services/trackbacks/29995.html</trackback:ping><description>&lt;DIV&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 加锁、解锁(同步/互斥)是多线程中非常基本的操作，但我却看到不少的代码对它们处理的很不好。简单说来有三类问题，一是加锁范围太大，虽然避免了逻辑错误，但锁了不该锁的东西，难免降低程序的效率；二是该锁的不锁，导致各种莫名其妙的错误；三是加锁方式不合适，该用临界区的用内核对象等，也会降低程序的效率。&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 要正确的运用锁操作，首先要弄清楚什么时候需要加锁。很多书上都说在可能&amp;#8220;同时发生多个写操作&amp;#8221;或&amp;#8220;同时发生读写操作&amp;#8221;时，应该加锁。这固然没什么错，但我认为它没有说到问题的根上，更准确的表述应该是：如果不加锁会导致不可容忍的数据不一致，那么就应该加锁。据此，我在下表中列出了多线程中应该加锁和无需加锁的条件，其中的&amp;#8220;简单数据类型&amp;#8221;是指cpu可以在一条指令中完成操作的数据类型，一般整形和所有比整形小的数据类型都是，除此之外的类型都属于&amp;#8220;复杂数据类型&amp;#8221;，例如你自己定义的结构体等。&lt;BR&gt;
&lt;TABLE style="WIDTH: 590px; HEIGHT: 87px" cellSpacing=1 cellPadding=1 width=590 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;操作的结果与初值无关&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;操作的结果与初值相关&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;写简单数据类型&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;不需要加锁①&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;需要加锁②&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;写复杂数据类型&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;需要加锁③&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;需要加锁④&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;读简单数据类型&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;不需要加锁⑤&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;不需要加锁⑥&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;读复杂数据类型&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;需要加锁⑦&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;需要加锁⑧&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 大家可能注意到，在第1、5、6种情况下，我认为可以不加锁，粗看起来，这与书上的说法有些矛盾。其实却不然，因为这些操作可以在一条指令内完成，所以它们具有天然的&amp;#8220;原子性&amp;#8221;，我们可以认为cpu已经给它们加锁了，我们没必要再画蛇添足。如果这个理由还不够的话，你不妨想一下我们再加一次锁是否有用，看下面的代码(以第1种情况为例)： 
&lt;TABLE style="BORDER-COLLAPSE: collapse" borderColor=#999999 cellSpacing=0 cellPadding=0 width="75%" bgColor=#f1f1f1 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;P style="MARGIN: 5px; LINE-HEIGHT: 150%"&gt;&lt;CODE&gt;&lt;SPAN style="COLOR: #000000"&gt;Lock&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff9900"&gt;// ①&lt;BR&gt;&lt;/SPAN&gt;n &lt;SPAN style="COLOR: #0000cc"&gt;=&lt;/SPAN&gt; 10&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff9900"&gt;// ②&lt;BR&gt;&lt;/SPAN&gt;Unlock&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff9900"&gt;// ③&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt; x &lt;SPAN style="COLOR: #0000cc"&gt;=&lt;/SPAN&gt; n&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff9900"&gt;// ④&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/CODE&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;看出来了吗？不管语句①③是否存在，这段代码执行完毕后，我们都无法保证x的值是10。也许你会想如果把③④两条语句的位置换一下，x就肯定是10了。可是在这个例子中，想让x是10，为什么不把语句④直接换成&amp;#8220;int x = 10;&amp;#8221;呢？既省了加锁，有减少了键盘的磨损，何乐而不为？！而且，我的这个例子并不是刻意构造的，在多线程，这种情况比比皆是。 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 第2种情况的典型代表是&amp;#8220;i++;&amp;#8221;，需要对它加锁是因为它表面上虽然只有一条语句，却要执行至少两个操作，一是读出i的初始, 二是把加一后的结果写回去，两个操作就没有&amp;#8220;原子性&amp;#8221;了，所以需要加锁。&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 另外，上表中判断是否需要加锁的依据是&amp;#8220;是否可能造成数据不一致&amp;#8221;。实际上，有些情况下数据不一致是可以容忍的,如果它发生概率极低、造成的不良后果可以忽略、并能很快自动恢复，那它可能就是可以容忍的。对这种数据不一致，我们可以不加锁。不过对它的判定与程序的实际情况关联太大，我们在这里就不讨论了。&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 加锁的方法也可分为三类，临界区、内核对象和互锁函数。相比前两类，互锁函数的知名度要低不少，但它却是我用的最多的方法，因为它有一个最大的优点：快！有不少书上比较临界区和内核对象时都说临界区的优点是不会进入内核模式，速度快。不过这是不全面的，如果没有冲突(实际发生冲突的概率一般很低)，临界区确实不会进内核模式，但如果发生了冲突要进行等待，它就要依靠内核对象了。而互锁函数则绝不会进内核模式，所以互锁函数是最快的(临界区在没有冲突时的行为是依靠互锁函数实现的)。互锁函数的缺点是只能处理相对简单的数据类型(不要和我前面说的&amp;#8220;简单数据类型&amp;#8221;等价起来)，但另一方面，对加锁需求最高的也往往是这些类型的数据。&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 实际开发中，还有一种锁比较常用，这就是单写多读锁，《windows核心编程》上有一个单写多读锁的实现，我的blog上有另一个实现。前者适用于需加锁的对象数量较少(例如如只有一个)，访问冲突概率相对较高的情况。后者适用于需加锁的对象很多，访问冲突概率很低的情况(对象多了, 单个对象的访问冲突自然就少了)。两个实现的共同缺点是不支持重入，即同一个线程中，解锁前不能再次加锁。临界区在这方面有优势，它支持重入。使用TLS(线程局部存储)技术进行改进应该能让它们支持重入，不过这样做了以后我那个实现应该就算不上轻量级了:)。&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 最后，还有其它的一些不用锁的方法也可以保证多线程中的数据一致性，其中最常用的就是循环。例如下面的例子：&lt;BR&gt;
&lt;TABLE style="BORDER-COLLAPSE: collapse" borderColor=#999999 cellSpacing=0 cellPadding=0 width="75%" bgColor=#f1f1f1 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;P style="MARGIN: 5px; LINE-HEIGHT: 150%"&gt;&lt;CODE&gt;&lt;SPAN style="COLOR: #000000"&gt;&lt;SPAN style="COLOR: #0000ff"&gt;struct&lt;/SPAN&gt; bar&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;{&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;volatile&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;unsigned&lt;/SPAN&gt; version&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #ff9900"&gt;// 一个额外的版本号字段&lt;BR&gt;&lt;/SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt; field1&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;char&lt;/SPAN&gt; field2&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;char&lt;/SPAN&gt; field3&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;}&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;bar g_bar &lt;SPAN style="COLOR: #0000cc"&gt;=&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000cc"&gt;{&lt;/SPAN&gt; 0 &lt;SPAN style="COLOR: #0000cc"&gt;}&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #ff9900"&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/CODE&gt;&lt;/P&gt;
&lt;P style="MARGIN: 5px; LINE-HEIGHT: 150%"&gt;&lt;CODE&gt;&lt;SPAN style="COLOR: #000000"&gt;&lt;SPAN style="COLOR: #ff9900"&gt;// 写线程&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;+&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;+&lt;/SPAN&gt;g_bar&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;version&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #ff9900"&gt;// 加1, version是奇数, 表示正在更新&lt;BR&gt;&lt;/SPAN&gt;g_bar&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;field1 &lt;SPAN style="COLOR: #0000cc"&gt;=&lt;/SPAN&gt; 10&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;+&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;+&lt;/SPAN&gt;g_bar&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;version&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #ff9900"&gt;// 再加1, version是偶数, 表示更新完毕&lt;BR&gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #ff9900"&gt;// 读线程&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; ReadGlobalBar&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt; bar&lt;SPAN style="COLOR: #0000cc"&gt;*&lt;/SPAN&gt; p &lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: #0000cc"&gt;{&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;unsigned&lt;/SPAN&gt; ver&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;do&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000cc"&gt;{&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ver &lt;SPAN style="COLOR: #0000cc"&gt;=&lt;/SPAN&gt; g_bar&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;version&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt; ver &lt;SPAN style="COLOR: #0000cc"&gt;%&lt;/SPAN&gt; 2 &lt;SPAN style="COLOR: #0000cc"&gt;!&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;=&lt;/SPAN&gt; 0 &lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #ff9900"&gt;// 正在更新&lt;BR&gt;&lt;/SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000cc"&gt;{&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #ff0000"&gt;Sleep&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt; 0 &lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #ff9900"&gt;// 等待&lt;BR&gt;&lt;/SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000ff"&gt;continue&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000cc"&gt;}&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;p&lt;SPAN style="COLOR: #0000cc"&gt;-&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;&amp;gt;&lt;/SPAN&gt;field1 &lt;SPAN style="COLOR: #0000cc"&gt;=&lt;/SPAN&gt; g_bar&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;field1&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: #0000cc"&gt;}&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;while&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;(&lt;/SPAN&gt; ver &lt;SPAN style="COLOR: #0000cc"&gt;!&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;=&lt;/SPAN&gt; g_bar&lt;SPAN style="COLOR: #0000cc"&gt;.&lt;/SPAN&gt;version &lt;SPAN style="COLOR: #0000cc"&gt;)&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000cc"&gt;;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/CODE&gt;&lt;/P&gt;
&lt;P style="MARGIN: 5px; LINE-HEIGHT: 150%"&gt;&lt;CODE&gt;&lt;SPAN style="COLOR: #000000"&gt;&lt;FONT face=新宋体&gt;&lt;SPAN style="COLOR: #0000cc"&gt;}&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/CODE&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;然而这种方法真的没用锁吗？看你怎么理解了，那个version字段其实就可以看做是锁的。不过它只是半个锁，因为它只锁了读操作，而没锁写操作，也就是说写操作可以随时进行而无需等待。如果读操作非常多，但写操作较少，并且你不希望写操作经常被打断，那它正好满足你的要求。它的缺点是你要保证系统中某个时刻最多有一个&amp;#8220;writer&amp;#8221;，&amp;#8220;writer&amp;#8221;一多，它就的无能为力了(这时一般应该用单写多读锁)。 
&lt;DIV&gt;&lt;BR&gt;&lt;STRONG&gt;2007.10.18：补充一点，关于acquire release semantics&lt;/STRONG&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; 在多处理器平台上，一个处理器的实际的操作顺序，和其它处理器所看到的它的操作顺序可能并不相同，例如：&lt;BR&gt;a++;&lt;BR&gt;b++;&lt;BR&gt;在其他处理器看来，很有可能&amp;#8220;b++&amp;#8221;发生在前面，而&amp;#8220;a++&amp;#8221;发生在后面。某些情况下，其他处理器看到的顺序必须和实际的顺序保持一致，所以就需要引入acquire semantics和release semantics了。&lt;BR&gt;&amp;nbsp;&amp;nbsp; 说一个操作具有acquire semantics，就表示可以保证其它处理器在看到这一操作的结果前，不会看到(该处理器上)后续操作的结果，对该处理器而言，可以理解为它进行此操作前，不会进行后续操作；而一个操作具有release semantics，就表示可以保证其它处理器在看到这一操作的结果前，能看到(该处理器)上先前所有操作的结果，对该处理器而言，可以理解为在完成所有先前的操作之前，不会进行此操作。&lt;BR&gt;&amp;nbsp;&amp;nbsp; vc编译器(其它编译器不一定保证)保证对volatile对象的写操作具有release semantics；对volatile对象的读操作具有acquire semantics。基于此点保证，多线程环境中就可以用volatile型对象实现锁操作了。&lt;BR&gt;&lt;BR&gt;&lt;A id=CategoryEntryList1_EntryStoryList_Entries__ctl12_TitleUrl href="/localvar/archive/2005/10/22/13826.html"&gt;&lt;FONT color=#006666&gt;对windows互锁函数的补充&lt;/FONT&gt;&lt;/A&gt;&lt;BR&gt;&lt;A id=CategoryEntryList1_EntryStoryList_Entries__ctl6_TitleUrl href="/localvar/archive/2007/01/23/24160.html"&gt;&lt;FONT color=#006666&gt;一个轻量级的单写多读锁&lt;/FONT&gt;&lt;/A&gt;&lt;/DIV&gt;&lt;img src ="http://blog.vckbase.com/localvar/aggbug/29995.html" width = "1" height = "1" /&gt;</description></item></channel></rss>