联锁阅读在哪里?
Win32 api 有一组 InterlockedXXX 函数来原子地、同步地操作简单变量,但是似乎没有任何 InterlockedRead 函数来简单地检索变量的值。 怎么会?
MSDN 说 :
对正确对齐的 32 位变量的简单读取和写入是原子操作
,但增加了:
但是,不保证访问是同步的。 如果两个线程正在读取和写入同一变量,则无法确定一个线程是否会在另一个线程执行写入操作之前执行读取操作。
据我了解,这意味着可以在执行另一个(例如 InterlockedAdd)操作时对变量进行简单的读取操作。 那么为什么没有一个互锁函数来读取变量呢?
我猜想该值可以被读取为 InterlockedAdd-ing 零的结果,但这似乎不是正确的方法。
Win32 api has a set of InterlockedXXX functions to atomically and synchronously manipulate simple variables, however there doesn't seem to be any InterlockedRead function, to simply retrive the value of the variable. How come?
MSDN says that:
Simple reads and writes to properly-aligned 32-bit variables are atomic operations
but adds:
However, access is not guaranteed to be synchronized. If two threads are reading and writing from the same variable, you cannot determine if one thread will perform its read operation before the other performs its write operation.
Which means, as I understand it, that a simple read operation of a variable can take place while another, say, InterlockedAdd operation is in place. So why isn't there an interlocked function to read a variable?
I guess the value can be read as the result InterlockedAdd-ing zero, but that doesn't seem the right way to go.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
实现此目的的正常方法是使用两个值相同的比较交换操作(例如InterlockedCompareExchange64)。 由于某种原因,我偷偷怀疑这比加 0 更有效,但我没有证据支持这一点。
有趣的是,.NET 的
Interlocked
类没有获得Read
方法直到 .NET 2.0。 我相信
Interlocked.Read
是使用Interlocked.CompareExchange
实现的。 (请注意,Interlocked.Read
的文档让我觉得有些误导 - 它讨论的是原子性,而不是波动性,这意味着 .NET 上非常具体的东西。我不确定 Win32 内存模型是什么保证来自不同线程的新写入值的可见性(如果有的话)。The normal way of implementing this is to use a compare-exchange operation (e.g.
InterlockedCompareExchange64
) where both values are the same. I have a sneaking suspicion this can be performed more efficiently than an add of 0 for some reason, but I have no evidence to back this up.Interestingly, .NET's
Interlocked
class didn't gain aRead
method until .NET 2.0. I believe thatInterlocked.Read
is implemented usingInterlocked.CompareExchange
. (Note that the documentation forInterlocked.Read
strikes me as somewhat misleading - it talks about atomicity, but not volatility, which means something very specific on .NET. I'm not sure what the Win32 memory model guarantees about visibility of newly written values from a different thread, if anything.)我认为你对“不同步”的解释是错误的。 简单的读取是原子的,但您必须自己处理重新排序和内存可见性问题。 前者是通过在适当的位置使用栅栏指令来处理的,后者对于读取来说不是问题(但潜在的并发写入必须确保适当的可见性,互锁函数应该这样做if< /em> 它们映射到锁定的 asm 指令)。
I think that your interpretation of "not synchronized" is wrong. Simple reads are atomic, but you have to take care of reordering and memory visibility issues yourself. The former is handled by using fence instructions at appropriate places, the latter is a non-issue with read (but a potential concurrent write has to ensure proper visibility, which Interlocked functions should do if they map to LOCKED asm instructions).
整个讨论的关键是正确的对齐,这是在 xxx 的分区 I 的“
12.6.2 对齐
”部分中定义的:基本上,所有 32 位值都具有所需的对齐,并且在64 位平台上,64 位值也具有所需的对齐方式。
但请注意:有些属性可以显式更改内存中类的布局,这可能会导致您失去这种对齐方式。 不过,这些属性是专门用于此目的的,因此除非您打算更改布局,否则这不适用于您。
排除了这一点,Interlocked 类的目的是提供(解释一下)只能在“之前”或“之后”状态下观察到的操作。 互锁操作通常仅在修改内存时才需要关注(通常以某种重要的比较交换类型的方式)。 正如您找到的 MSDN 文章所示,读取操作(正确对齐后)始终可以被视为原子操作,无需采取进一步的预防措施。
然而,在处理读取操作时还有其他考虑因素:
Interlocked.Read
操作来保证整体 64 位值在单个原子操作中读取(否则它可能作为 2 个单独的 32 位读取来执行,这些读取可以来自内存更新的任一侧)Interlocked
类操作)简短摘要; 就原子性而言,您正在做的事情很可能不需要任何特殊的阅读说明……但是,您可能还需要注意其他事情,具体取决于您正在做什么。
The crux of this whole discussion is proper alignment, which is devined in Partition I of xxx, in section '
12.6.2 Alignment
':Basically, all 32-bit values have the required alignment, and on a 64-bit platform, 64-bit values also have the required alignment.
Note though: There are attributes to explicitly alter the layout of classes in memory, which may cause you to lose this alignment. These are attributes specificially for this purpose though, so unless you have set out to alter the layout, this should not apply to you.
With that out of the way, the purpose of the
Interlocked
class is to provide operations that (to paraphrase) can only be observed in their 'before' or 'after' state. Interlocked operations are normally only of concern when modifying memory (typically in some non-trivial compare-exchange type way). As the MSDN article you found indicates, read operations (when properly aligned) can be considered atomic at all times without further precautions.There are however other considerations when dealing with read operations:
Interlocked.Read
operation to guarantee the whole 64-bit value is read in a single atomic operation (otherwise it may be performed as 2 separate 32-bit reads which can be from either side of a memory update)Interlocked
class operations)Short summary; as far as atomicity goes, it is very likely that what you are doing does not need any special instruction for the read... there may however be other things you need to be careful of, depending on what exactly you are doing.