windows - 如何理解acquire和release语义?

标签 windows

我从 MSDN 中找到了三个函数,如下:

1.InterlockedDecrement().

2.InterlockedDecrementAcquire().

3.InterlockedDecrementRelease().

我知道那些函数用来递减一个值作为原子操作,但我不知道这三个函数之间的区别

最佳答案

(um... but don't ask me what does it mean exactly)

我会尝试一下。

需要记住的是,编译器或 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 或编译器上创建无锁数据结构是可能的,但这通常意味着使用了一些较慢的内存排序语义。例如,您可以发出一个完整的内存屏障——在该指令之前的所有内容都必须在该指令之前实际提交,而在该指令之后的所有内容都必须在该指令之后实际提交。但这可能意味着我在指令流中等待一堆实际上不相关的内存写入(可能是函数调用序言),这与我试图实现的内存安全无关。

Acquire 说“只担心我之后的事情”。发布说“只担心我面前的事情”。将两者结合起来就是一个完整的内存屏障。

关于windows - 如何理解acquire和release语义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24565540/

相关文章:

windows - Windows 上共享内存的映射 View 数

windows - CP 命令提示符 Windows 7 无法识别

windows - Windows 中事件进程列表的用途?

Windows 批处理,仅选择用户变量

windows - winget 源代码库的结构

c# - 事件查看器中的行号

windows - 您可以将 Kinect for Xbox 用于 Kinect Fusion 吗?

c++ - boost::asio 中 TCP 数据包的数量由什么决定?

windows - 如何根据操作系统系列具有不同的依赖关系

javascript - 如何使用 JavaScript 打开 Windows 程序?