繁体   English   中英

易挥发,确保新鲜度

[英]Volatile.Write freshness guarentee

Volatile.Write的文档中指出以下内容:

将指定的对象引用写入指定的字段。 在需要它的系统上,插入一个内存屏障,以防止处理器按以下方式重新排序内存操作:如果在代码中此方法之前出现了读取或写入操作,则处理器无法在此方法之后移动它。

T
要写入的对象引用。 该引用将立即写入,以便对计算机中的所有处理器可见。

但似乎引号1和2是矛盾的。

为了使第二个引用正确,我认为第一个引用必须进行如下更改:

如果读或写在代码此方法出现 之前 ,处理器不能此方法之前 移动它。

Volatile.Write真的意味着可以保证其他线程可以及时地进行写操作,还是第二个引号引起误解?

在我看来,似乎所有这些“可变” /“内存壁垒”似乎都集中在确保如果将写暴露给其他线程,则它们以正确的顺序暴露,但是我似乎找不到真正的含义。强迫他们暴露。

我了解可能很难/不可能立即将写入公开给其他线程,但是在没有不稳定的写入/读取的情况下,有些情况下永远不会公开写入。 因此,似乎必须有一种方法可以确保“最终”公开写入,但是我不确定那是什么。 是写入始终在.NET公开,但读取可以被缓存吗? 如果是这样,那么Volatile.Read停止这种缓存行为吗?

(请注意,我已经阅读了Joseph Albahari的C#中的Threading,它倾向于表明我在读和写之后需要显式的内存屏障,尽管目前尚不清楚为什么这样有效,因为Thread.MemoryBarrier的文档似乎并不有效。明确地说写被显示给其他线程)。

您有点误解了障碍的概念。 如你所写

要写入的对象引用。 该引用将立即写入,以便对计算机中的所有处理器可见。

因此,这里真正重要的单元是处理器,而不是线程。

因此,涉及到处理器,处理器高速缓存,存储缓冲区和失效队列。
当处理器将某些内容写入内存时,看起来像是类似的东西 在此处输入图片说明

主题处于存储缓冲区级别。 如您所见,当您写东西或读东西时,有很多事情在发生,并且并不是系统中所有处理器都会立即发生。 在开始时,将读取或写入命令放入处理器的存储缓冲区,并且这些命令可以重新排序,换句话说,由处理器以不同的顺序执行。

发生这种情况时,其他处理器不知道更改,如果操作是写操作,并且当前工作的处理器不知道其他处理器进行的更改。

放置屏障时,这意味着在执行任何读取或写入操作之前,应先完成存储缓冲区或失效队列中的操作。 这对于跨处理器实现CPU缓存是必需的 因此,基本上没有机制可以跨线程同步任何数据,我们可以跨处理器同步数据。

当线程A在处理器1上写一些东西,而线程B在处理器1上写一些东西时,它们都首先查看存储缓冲区,因此它们读取实际数据,无论是否设置了障碍。

这只是所涉及机制的概述,也许我在某些细节上是错误的。 如果您阅读了有关MESI协议的信息,则可以找到完整的信息, 此PDF带有有关无效队列和存储缓冲区的说明。

我同意您的观点,MSDN文档中的描述有些混乱。 我想说的是,“立即”在这里以及与并行处理相关的任何主题上都是强词。 结果将不会立即可见,但文档并未说明-它表示将立即写入值,也就是说,一旦所有先前的加载/存储操作结果在全局范围内可见,则写入值的存储操作将被立即写入。立即启动。

至于内存屏障,它们只能保证先前的操作暴露(全局可见性),因为本质上,内存屏障是CPU遇到的指令,使CPU“等待”以使全局所有未决的加载/存储操作可见而由Volatile.Write撰写的全球价值可见性时刻既不是障碍也不是Volatile.Write关注点。

现在有关在无锁编程中使用障碍的建议。 当然这是有道理的,因为它确保了多核系统实际的全局可见性顺序。 如果您不能确定事件B总是在事件A之后发生,那么您就无法构建可靠的逻辑,该逻辑应该在多核环境中执行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM