📄 01_9_17_2.asp.html
字号:
<html><head><meta http-equiv='Content-Type' content='text/html; charset=gb2312'>
<TITLE>计算机世界网-使用临界段实现优化的进程间同步对象</TITLE></HEAD>
<style>
.a14{font-size:14px;text-indent:25px;line-height:20px}
.f{font-size:18px;color=#0f3ccd}
img{border:0px;}
td,p,input{font-fammily:verdana,宋体;font-size:12px;}
A:link {text-decoration:none;color:black}
A:visited {text-decoration:none;color:#80006f}
A:hover {text-decoration:underline;color:black}
</style>
<center>
<BODY topmargin=2 leftmargin=0>
<style>
.v12{font-size:10pt;color:"#ffffff";FONT-WEIGHT: bold}
.v14{font-size:14px;text-indent:25px;line-height:20px}
img{border:0px;}
td,p,input,select{font-fammily:verdana,宋体;font-size:12px;}
A:link {text-decoration:none;color:black}
A:visited {text-decoration:none;color:#80006f}
A:hover {text-decoration:underline;color:black}
</style>
<style>
.v13{font-size:10pt;color:"#ffffff";FONT-WEIGHT: bold}
.v12{font-size:13px;color:"#4C029C";FONT-WEIGHT: bold}
.v14{font-size:14px;text-indent:25px;line-height:20px}
img{border:0px;}
td,p,input,select{font-fammily:verdana,宋体;font-size:12px;}
A:link {text-decoration:none;color:black}
A:visited {text-decoration:none;color:#80006f}
A:hover {text-decoration:underline;color:black}
</style>
<!--头-->
<table align=center cellpadding="0" cellspacing="0" border="0" width="767">
<tr><td valign=bottom>
<table cellpadding="0" cellspacing="0" border=0>
<tr><td valign=top><img src="../../../../../center/image/ccwlogo.gif"></td></tr>
<tr><td height="27" valign=top><img src="../../../../../center/image/knowledge.gif" width="207" height="27"></td></tr>
</table></td>
<td valign=bottom width=556 bgcolor="#4c029c" height=96>
<table cellpadding="0" cellspacing="0" border=0 width=556 bgcolor="#4c029c" height=96>
<tr><td height=25 valign=bottom bgcolor="#ffffff" colspan=2 ><img src="../../../../../image2002/top.gif" usemap="#F"></td></tr>
<tr valign=middle >
<td align=center valign=middle height="60" align=center>
<!-- <a href="http://www.ccw.com.cn/search/" target=_blank><img src="../../../../../img2/esearch.GIF" border=0 width=468 height=60></a> --><a href="http://www.ccw.com.cn/html/search/thememail/" target=_blank><img src="../../../../../img2/topbanner_thememail.GIF" border=0 width=468 height=60></a>
</td>
<td align=center width=15%>
<table width=95%>
<tr><td><a href="mailto:center@ccw.com.cn?subject=我要投稿:" target=_blank><font class=v13>我要投稿</a><br><a href="mailto:center@ccw.com.cn?subject=编读往来"><font class=v13>编读往来</a><br><a href="javascript:AddBookMark('计算机世界网首页')"><font class=v13>加入收藏</a></font></td></tr>
</table>
</td>
</tr>
<tr><td bgcolor="#ffffff" height=1 colspan=2 ></td></tr>
<tr><td bgcolor="#b4aafc" height=2 colspan=2 ></td></tr></table>
<map name="F">
<area href="http://www.ccw.com.cn/" shape="rect" coords="29, 3, 61, 18" target=_blank>
<area href="http://www.ccw.com.cn/news1/" shape="rect" coords="72, 3, 143, 18" target=_blank>
<area href="http://www.ccw.com.cn/center/" shape="rect" coords="155, 2, 216, 18" target=_blank>
<area href="http://www.ccw.com.cn/work/" shape="rect" coords="225, 2, 299, 18" target=_blank>
<area href="http://www.ccw.com.cn/search/" shape="rect" coords="310, 3, 364, 19" target=_blank>
<area href="http://www3.ccw.com.cn/" shape="rect" coords="372, 2, 412, 19" target=_blank>
<area href="http://www2.ccw.com.cn/" shape="rect" coords="424, 2, 550, 18" target=_blank></map>
</td></tr>
<tr><td colspan=2 bgcolor="#b4aafc">
<table border=0 cellpadding=0 cellspacing=0 width=100%>
<tr>
<td width=26% align=center><font class=v12>【2003年6月24日】 </font></td>
<td CLASS=V12> <a href="http://www.ccw.com.cn/center/topic.asp">专 题</a> /</td>
<td CLASS=V12><a href="http://www.ccw.com.cn/center/tech.asp">技 术</a> /</td>
<td CLASS=V12><a href="http://www.ccw.com.cn/center/prod.asp">产 品</a> /</td>
<td CLASS=V12><a href="http://www.ccw.com.cn/center/app.asp">应 用</a> /</td>
<td CLASS=V12><a href="http://www.ccw.com.cn/center/net.asp">网 络</a> /</td>
<td CLASS=V12><a href="http://www.ccw.com.cn/center/prog.asp">编 程</a> /</td>
<td CLASS=V12><a href="http://www.ccw.com.cn/center/skill.asp">技 巧</a> </td>
</tr>
</table>
</td></tr>
</table>
<table align=center width=728>
<tr><td align=center><br><h2><font color='#0f3ccd'>使用临界段实现优化的进程间同步对象</font></h2>
<br><b>vcbear</b>
</td></tr><tr><td align=right>01-9-17 上午 10:09:14<br><hr size=1 width=718 color=#f46240></td></tr></table><br>
<table align=center width=728><tr><td valign=top width=600>
<table width=100% ><tr><td class=a14>实现自己的同步对象?需要吗?</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
不需要吗?</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
...</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
只是跟你研究一下而已.</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
算了吧我只是个爱灌水的家伙,很久没有写代码了,闲来无事,灌灌水还不行吗?</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr>
<td class=a14> <b>1.概述:</b></td>
</tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
在多进程的环境里,需要对线程进行同步.常用的同步对象有临界段(Critical Section),互斥量(Mutex),信号量(Semaphore),事件(Event)等,除了临界段,都是内核对象。</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
在同步技术中,临界段(Critical Section)是最容易掌握的,而且,和通过等待和释放内核态互斥对象实现同步的方式相比,临界段的速度明显胜出.但是临界段有一个缺陷,WIN32文档已经说明了临界段是不能跨进程的,就是说临界段不能用在多进程间的线程同步,只能用于单个进程内部的线程同步.</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
因为临界段只是一个很简单的数据结构体,在别的进程的进程空间里是无效的。就算是把它放到一个可以多进程共享的内存映象文件里,也还是无法工作.</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
有甚么方法可以跨进程的实现线程的高速同步吗?</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr>
<td class=a14> <b>2.原理和实现</b></td>
</tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
2.1为什么临界段快? 是“真的”快吗?</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
确实,临界段要比其他的核心态同步对象要快,因为EnterCriticalSection和LeaveCriticalSection这两个函数从InterLockedXXX系列函数中得到不少好处(下面的代码演示了临界段是如何使用InterLockedXXX函数的)。InterLockedXXX系列函数完全运行于用户态空间,根本不需要从用户态到核心态</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
之间的切换。所以,进入和离开一个临界段一般只需要10个左右的CPU执行指令。而当调用WaitForSingleObject之流的函数时,因为使用了内核对象,线程被强制的在用户态和核心态之间变换。在x86处理器上,这种变换一般需要600个CPU指令。看到这里面的巨大差距了把。</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
话说回来,临界段是不是真正的“快”?实际上,临界段只在共享资源没有冲突的时候是快的。当一个线程试图进入正在被另外一个线程拥有的临界段,即发生竞争冲突时,临界段还是等价于一个event核心态对象,一样的需要耗时约600个CPU指令。事实上,因为这样的竞争情况相对一般的运行情况来说是很少的(除非人为),所以在大部分的时间里(没有竞争冲突的时候),临界段的使用根本不牵涉内核同步,所以是高速的,只需要10个CPU的指令。(bear说:明白了吧,纯属玩概率,Ms的小花招)</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
2.3进程边界怎么办?</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
“临界段等价于一个event核心态对象”是什么意思?</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
看看临界段结构的定义先</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
typedef struct _RTL_CRITICAL_SECTION {</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
PRTL_CRITICAL_SECTION_DEBUG DebugInfo;</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
//</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
// The following three fields control entering and exiting the critical</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
// section for the resource</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
//</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
LONG LockCount;</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
LONG RecursionCount;</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
HANDLE OwningThread; // from the thread's ClientId->UniqueThread</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
HANDLE LockSemaphore;</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
DWORD SpinCount;</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
#typedef RTL_CRITICAL_SECTION CRITICL_SECTION</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
在CRITICAL_SECTION 数据结构里,有一个Event内核对象的句柄(那个undocument的结构体成员LockSemaphore,包含的实际是一个event的句柄, 而不是一个信号量semaphore)。正如我们所知,内核对象是系统全局的,但是该句柄是进程所有的,而不是系统全局的。所以,就算把一个临界段结构直接放到共享的内存映象里,临界段也无法起作用,因为LockSemaphore里句柄值只对一个进程有效,对于别的进程是没有意义的。 在一般的进程同步中,进程要使用一个存在于别的进程里的Event 对象,必须调用OpenEvent或CreaetEvent函数来得到进程可以使用的句柄值。</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
CRITICAL_SECTION结构里其他的变量是临界段工作所依赖的元素,Ms也“警告”程序员不要自己改动该结构体里变量的值。是怎么实现的呢?看下一步.</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
2.4 COptex,优化的同步对象类</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
Jeffrey Richter曾经写过一个自己的临界段,现在,他把他的临界段改良了一下,把它封装成一个COptex类。成员函数TryEnter拥有NT4里介绍的函数TryEnterCriticalSection的功能,这个函数尝试进入临界段,如果失败立刻返回,不会挂起线程,并且支持Spin计数.这个功能在NT4/SP3中被InitializeCriticalSectionAndSpinCount 和SetCriticalSectionSpinCount实现。Spin计数在多处理器系统和高竞争冲突情况下是很有用的,在进入WaitForXXX核心态之前,临界段根据设定的Spin计数进行多次TryEnterCtriticalSection,然后才进行堵塞。想一下,TryEnterCriticalSection才使用10个左右的周期,如果在Spin计数消耗完之前,冲突消失,临界段对象是空闲的,那么再用10个CPU周期就可以在用户态进入临界段了,不用切换到核心态.</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr><td class=a14>
(bear说:为了避免这个"核心态",Ms自己也是费劲脑汁呀.看出来了吧,优化的原则:在需要的时候才进入核心态。否则,在用户态进行同步)</td></tr></table><table width=100% ><tr><td class=a14>
</td></tr></table><table width=100% ><tr>
<td class=a14> 以下是COptex代码。<a href="http://www.ccw.com.cn/htm/app/down/jq09_17_2.htm">原代码下载</a></td>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -