InterlockedRead在哪里?

时间:2009-07-05 18:33:10

标签: multithreading winapi interlocked

Win32 api有一组InterlockedXXX函数可以原子地和同步地操作简单变量,但是似乎没有任何InterlockedRead函数可以简单地检索变量的值。怎么样?

MSDN says

  

对正确对齐的32位变量的简单读取和写入是原子操作

但补充道:

  

但是,无法保证访问同步。但是,不保证访问同步。如果两个线程正在从同一个变量读取和写入,则无法确定一个线程是否会在另一个线程执行其写入操作之前执行其读取操作。

根据我的理解,这意味着变量的简单读取操作可以发生,而另一个,例如,InterlockedAdd操作就位。那么为什么没有互锁函数来读取变量?

我猜这个值可以作为InterlockedAdd-zero的结果读取,但这似乎不是正确的方法。

3 个答案:

答案 0 :(得分:8)

实现此目的的常规方法是使用比较交换操作(例如InterlockedCompareExchange64),其中两个值相同。我有一种潜在的怀疑,由于某种原因,这可以比添加0更有效地执行,但我没有证据支持这一点。

有趣的是,.NET的Interlocked类在.NET 2.0之前没有获得Read方法。我相信Interlocked.Read是使用Interlocked.CompareExchange实现的。 (请注意,Interlocked.Read的文档让我觉得有点误导 - 它谈论的是原子性,但不是波动性,这意味着.NET上非常具体的东西。我不确定Win32内存模型对新的可见性的保证来自不同线程的书面值,如果有的话。)

答案 1 :(得分:7)

我认为你对“不同步”的解释是错误的。简单读取 原子,但您必须自己处理重新排序和内存可见性问题。前者通过在适当的位置使用fence指令来处理,后者在读取时没有问题(但是潜在的并发写入必须确保正确的可见性,互锁函数 / em>他们映射到LOCKED asm指令)。

答案 2 :(得分:2)

整个讨论的关键是正确的对齐,它在xxx的分区I中,在“12.6.2 Alignment”部分中有所体现:

Built-in datatypes shall be properly aligned, which is defined as follows:
• 1-byte, 2-byte, and 4-byte data is properly aligned when it is stored at
  a 1-byte, 2-byte, or 4-byte boundary, respectively.
• 8-byte data is properly aligned when it is stored on the same boundary
  required by the underlying hardware for atomic access to a native int.

基本上,所有32位值都具有所需的对齐,而在64位平台上,64位值也具有所需的对齐。

注意:有些属性可以显式改变内存中类的布局,这可能会导致你失去这种对齐。这些属性是专门用于此目的的属性,因此,除非您已经着手改变布局,否则这不适用于您。

除此之外,Interlocked类的目的是提供只有在'之前'或'之后'状态下才能观察到的操作(换句话说)。在修改内存时通常只关注联锁操作(通常以某种非平凡的比较交换方式)。正如您发现的MSDN文章所示,读取操作(正确对齐时)可以始终被视为原子操作,无需采取进一步的预防措施。

处理读取操作时还有其他注意事项:

  • 在现代CPU上,尽管读取可能是原子的,但它也可能从某个过时的缓存中返回错误的值...这是您可能需要使字段“易变”以获得您期望的行为
  • 如果您在32位硬件上处理64位值,则可能需要使用Interlocked.Read操作来保证整个 64位值在单原子操作(否则它可以作为2个独立的32位读取执行,可以来自内存更新的任何一侧)
  • 重新排序您的读/写可能会导致您无法获得预期的价值;在这种情况下可能需要一些内存屏障(显式,或通过使用Interlocked类操作)

简短摘要;就原子性而言,你正在做的事情很可能不需要任何特殊的阅读指令......但是你可能需要注意其他事情,这取决于你究竟在做什么。