联锁阅读在哪里?

发布于 2024-07-26 18:43:33 字数 572 浏览 4 评论 0原文

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

陈甜 2024-08-02 18:43:33

实现此目的的正常方法是使用两个值相同的比较交换操作(例如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 a Read method until .NET 2.0. I believe that Interlocked.Read is implemented using Interlocked.CompareExchange. (Note that the documentation for Interlocked.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.)

软的没边 2024-08-02 18:43:33

我认为你对“不同步”的解释是错误的。 简单的读取是原子的,但您必须自己处理重新排序和内存可见性问题。 前者是通过在适当的位置使用栅栏指令来处理的,后者对于读取来说不是问题(但潜在的并发写入必须确保适当的可见性,互锁函数应该这样做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).

美男兮 2024-08-02 18:43:33

整个讨论的关键是正确的对齐,这是在 xxx 的分区 I 的“12.6.2 对齐”部分中定义的:

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类操作)

简短摘要; 就原子性而言,您正在做的事情很可能不需要任何特殊的阅读说明……但是,您可能还需要注意其他事情,具体取决于您正在做什么。

The crux of this whole discussion is proper alignment, which is devined in Partition I of xxx, in section '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.

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:

  • On modern CPUs, although the read may be atomic, it also may return the wrong value from a stale cache somewhere... this is where you may need to make the field 'volatile' to get the behaviour you expect
  • If you are dealing with a 64-bit value on 32-bit hardware, you may need to use the 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)
  • Re-ordering of your reads / writes may cause you to not get the value you expected; in which case some memory barrier may be needed (either explicit, or through the use of the 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文