如何理解获取和释放语义?

时间:2014-07-04 01:33:30

标签: windows

我在MSDN中发现了三个功能,如下:

1.InterlockedDecrement().

2.InterlockedDecrementAcquire().

3.InterlockedDecrementRelease().

我知道那些功能用于将值减少为原子操作,但我不知道三个功能之间的区别

2 个答案:

答案 0 :(得分:5)

  

(嗯......但不要问我到底是什么意思)

我会捅那个。

需要记住的是,编译器或CPU本身可能会重新排序内存读写,如果它们看起来没有相互处理。

这很有用,例如,如果您有一些代码,可能正在更新结构:

if ( playerMoved ) {
  playerPos.X += dx;
  playerPos.Y += dy; 

  // Keep the player above the world's surface.
  if ( playerPos.Z + dz > 0 ) {
     playerPos.Z += dz;
  }
  else {
     playerPos.Z = 0;
  }
}

上述大多数语句可能会被重新排序,因为它们之间没有数据依赖关系,事实上,超标量CPU可能会同时执行大多数语句,或者可能会更快地开始处理Z部分,因为它不会影响X或Y,但可能需要更长的时间。

这就是问题所在 - 让我们说你正在尝试无锁编程。你想要执行一大堆内存写入,也许,填写一个共享队列。你终于写下了一面旗帜,表明你已经完成了。

好吧,由于该标志似乎与正在完成的其余工作无关,编译器和CPU可能会重新排序这些指令,现在您可以在实际提交之前设置“完成”标志。结构的其余部分到内存,现在你的“无锁”队列不起作用。

这是Acquire和Release排序语义发挥作用的地方。我通过使用Acquire语义设置一个标志左右来设置我正在做的工作,并且CPU保证我在该指令之后播放的任何记忆游戏实际上都低于该指令。我设置我已经通过设置一个标记左右的Release语义来完成,并且CPU保证我在发布之前所做的任何内存游戏实际上都在发布之前保留。

通常,人们可以使用显式锁 - 互斥锁,信号量等来实现这一点,其中CPU已经知道它必须注意内存排序。尝试创建“无锁”数据结构的关键是提供线程安全的数据结构(对于某些线程安全的含义),它们不使用显式锁(因为它们非常慢)。

在不支持获取/发布排序语义的CPU或编译器上创建无锁数据结构,但它通常意味着使用一些较慢的内存排序语义。例如,您可以发出一个完整的内存屏障 - 在此指令之前必须实际提交的所有内容都必须在此指令之前提交,并且此指令之后的所有内容必须在此指令之后实际提交。但这可能意味着我等待早期在指令流(可能是函数调用序言)中的一堆实际上无关的内存写入与我试图实现的内存安全无关。

获取说“只关心我后面的东西”。发布说“只担心我面前的事情”。将两者结合起来是一个完全的记忆障碍。

答案 1 :(得分:2)

http://preshing.com/20120913/acquire-and-release-semantics/

  

获取语义是一种只能应用于操作的属性   它从共享内存中读取,是否为读 - 修改 - 写   操作或普通负载。然后将该操作视为a   读获取。获取语​​义可以防止内存重新排序   通过其后的任何读或写操作进行读取   程序顺序。

     

发布语义是一种只能应用于操作的属性   写入共享内存,是否为读 - 修改 - 写   经营或平原店。然后将该操作视为a   写释放。释放语义可防止内存重新排序   使用任何读取或写入操作进行写入释放   程序顺序。

(嗯......但不要问我这是什么意思完全