Win32 api有一组InterlockedXXX函数可以原子地和同步地操作简单变量,但是似乎没有任何InterlockedRead函数可以简单地检索变量的值。怎么样?
对正确对齐的32位变量的简单读取和写入是原子操作
但补充道:
但是,无法保证访问同步。但是,不保证访问同步。如果两个线程正在从同一个变量读取和写入,则无法确定一个线程是否会在另一个线程执行其写入操作之前执行其读取操作。
根据我的理解,这意味着变量的简单读取操作可以发生,而另一个,例如,InterlockedAdd操作就位。那么为什么没有互锁函数来读取变量?
我猜这个值可以作为InterlockedAdd-zero的结果读取,但这似乎不是正确的方法。
答案 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文章所示,读取操作(正确对齐时)可以始终被视为原子操作,无需采取进一步的预防措施。
处理读取操作时还有其他注意事项:
Interlocked.Read
操作来保证整个 64位值在单原子操作(否则它可以作为2个独立的32位读取执行,可以来自内存更新的任何一侧)Interlocked
类操作)简短摘要;就原子性而言,你正在做的事情很可能不需要任何特殊的阅读指令......但是你可能需要注意其他事情,这取决于你究竟在做什么。