互锁的原子操作

Intel CPU相关指令: LOCK 这是一个指令前缀,在所对应的指令操作期间使此指令的目标操作数指定的存储区域锁定,以得到保护。 XADD 先交换两个操作数的值,再进行算术加法操作。多处理器安全,在80486及以上CPU中支持。 CMPXCHG 比较交换指令,第一操作数先和AL/AX/EAX比较,如果相等ZF置1,第二操作数赋给第一操作数,否则ZF清0,第一操作数赋给AL/AX/EAX。 多处理器安全,在80486及以上CPU中支持。 CMPXCHG8B 同上,64位比较交换指令,第二操作数隐含为EDX:EAX,比较EDX:EAX与64位的目标,如果相等则ECX:EBX送往目标且ZF置1,否则目标送EDX:EAX且ZF清0。 windows互锁API列表: InterlockedCompareExchange/InterlockedCompareExchange64 InterlockedCompareExchangeAcquire/InterlockedCompareExchangeAcquire64 InterlockedCompareExchangePointer InterlockedCompareExchangeRelease/InterlockedCompareExchangeRelease64 InterlockedDecrement/InterlockedDecrement64 InterlockedDecrementAcquire InterlockedDecrementRelease InterlockedExchange/InterlockedExchange64 InterlockedExchangeAcquire64 InterlockedExchangeAdd/InterlockedExchangeAdd64 InterlockedExchangePointer InterlockedIncrement/InterlockedIncrement64 InterlockedIncrementAcquire InterlockedIncrementRelease 多处理器安全就是当某值被某处理器修改后,其他处理器应当知晓,而不再使用CPU缓存内的旧数据。 本文不讨论WinNT3.51/Win95以及更早的操作系统(它们是为80386设计的),以及安装在80386上的Win98(Win98安装时自动判断是否支持XADD指令)。 看一个简单的函数,它的作用是将lpAddend加1,并返回之。 LONG InterlockedIncrement( LPLONG lpAddend ) { MOV ecx, lpAddend MOV eax, 1 LOCK XADD dword ptr [ecx], eax INC eax RET 4 } 看一个复杂的函数,它的作用是将lValue赋值给*plTarget,并返回*plTarget的原先值。 LONG InterlockedExchange( LPLONG plTarget, LONG lValue ) { MOV ecx, plTarget MOV edx, lValue MOV eax, dword ptr [ecx] L: LOCK CMPXCHG dword ptr [ecx], edx JNE L RET 8 } 看,不得不动用了一个循环指令。类似的还有InterlockedCompareExchange(pdestination,exchage,comperand)函数,如果Destination等于Comperand,将Exchange赋值给Destination,否则什么也不干,返回值为Destination的原先值。 循环技巧是很有用的,Jeffrey Richter给出了一个功能代码,如果值大于0,则加1,代码如下: do { LONG lStartValue = *plTarget; LONG lNewValue = lStartValue + ((lStartValue > 0) ? 1 : 0); } while( InterlockedCompareExchange(plTarget,lNewValue,lStartValue) != lStartValue ); 一个未知的问题是,为什么在有的操作系统中没看到LOCK。未来的研究是线程/进程锁。 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、 互锁函数是多线程处理中最简单高效的手段之一,但这些函数的功能实在是太差劲了,要求稍微复杂一点,就完成不了。比如“if( n > 100 ) n++;”这么简单的功能,它们就做不到。以前,为了达到互斥的目的,我都要使用一个临界区,现在想想,这个方法简直太笨了!因为借助InterlockedCompareExchange,甚至更复杂的功能都可以轻松实现,而这个函数曾经是我认为的最没用的互锁函数。例如前面的大于某值才加1的功能就可以通过下面这个函数以原子的形式完成: LONG InterlockedBiggerExchangeAdd( LONG volatile* Addend, LONG Value, LONG Comperand ) throw() { LONG lOrigin; do lOrigin = *Addend; while( (lOrigin > Comperand) && (::InterlockedCompareExchange(Addend, lOrigin + Value, lOrigin) != lOrigin) ); return lOrigin; } 这个函数比较*Addend和Comperand, 如果*Addend大于Comperand, 就给*Addend加上Value, 返回值则是*Addend的初值。 仿照上面的例子,我们还可以写出InterlockedAnd、InterlockedOr和InterlockedXor的实现,这也是我以前经常抱怨的,因为系统只在ddk中提供了它们!但话说回来,这三个函数还有更简单的实现方式,因为汇编指令and、or、xor都支持lock前缀,如果直接用汇编实现的话,会更简单高效! 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、 以下内容收集整理于Richter的《Windows核心编程》: 8.1 原子访问:互锁的函数家族 线程同步问题在很大程度上与原子访问有关,所谓原子访问,是指线程在访问资源时能够确保所有其他线程都不在同一时间内访问相同的资源。 LONG InterlockedExchangeAdd( PLONG plAddend, LONG Increment); 这是个最简单的函数了。只需调用这个函数,传递一个长变量地址,并指明将这个值递增多少即可。这个函数能够保证值的递增以原子操作方式来完成。 LONG InterlockedExchange(PLONG plTarget, LONG lValue); //可用于指针与结构体等数据的原子交换 PVOID InterlockedExchangePointer(PVOID* ppvTarget, PVOID pvValue); InterlockedExchange和InterlockedExchangePointer能够以原子操作方式用第二个参数中传递的值来取代第一个参数中传递的当前值。如果是32位应用程序,两个函数都能用另一个32位值取代一个32位值。但是,如果是个64位应用程序,那么InterlockedExchange能够取代一个32位值,而InterlockedExchangePointer则取代64位值。两个函数都返回原始值。当实现一个循环锁时,InterlockedExchange是非常有用的。 下面是最后两个互锁函数: PVOID InterlockedCompareExchange(PLONG plDestination, LONG lExchange, LONG lComparand); PVOID InterlockedCompareExchangePointer(PVOID* ppvDestination, PVOID pvExchange, PVOID pvComparand); 这两个函数负责执行一个原子测试和设置操作。如果是32位应用程序,那么两个函数都在32位值上运行,但是,如果是64位应用程序,InterlockedCompareExchange函数在32位值上运行,而InterlockedCompareExchangePointer函数则在64位值上运行。 在伪代码中,它的运行情况如下面所示: LONG InterlockedCompareExchange(PLONG plDestination, LONG lExchange, LONG lComparand) { LONG lRet = *plDestination; //Original value if(*plDestination == lComparand) { *plDestination = lExchange; } return(lRet); } 该函数对当前值( plDestination 参数指向的值)与lComparand参数中传递的值进行比较。如果两个值相同,那么* plDestination 改为lExchange参数的值。如果* plDestination 中的值与lExchange的值不匹配, * plDestination 保持不变。该函数返回* plDestination 中的原始值。记住,所有这些操作都是作为一个原子执行单位来进行的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值