1

在下面的代码示例中,是否需要FuncA中的内存屏障来确保读取最新的值?

class Foo
{
   DateTime m_bar;

   void FuncA() // invoked by thread X
   {
      Thread.MemoryBarrier(); // is required?
      Console.WriteLine(m_bar);
   }

   void FuncB() // invoked by thread Y
   {
       m_bar = DateTime.Now;
   }       
}

编辑:如果没有,我如何确保 FuncA 将读取最新值?(我想确保最近的值实际上存储在处理器的缓存中)[不使用锁]

4

5 回答 5

2

对我来说,这似乎是一个很大的“不”。Thread.MemoryBarrier() 仅在实现它的线程内同步内存访问。

来自 MSDN:

执行当前线程的处理器不能以这样一种方式重新排序指令,即在调用 MemoryBarrier 之前的内存访问在调用 MemoryBarrier 之后的内存访问之后执行。

于 2009-11-13T19:56:52.973 回答
2

我建议您将 Datetime 存储为刻度数(它是“long”类型,即 Int64),您可以轻松地从刻度(新 DateTime(刻度))转换为刻度(myDateTime.Ticks)。然后您可以使用 Interlocked.Read 读取值并使用 Interlocked.Exchange 在快速非锁定操作中写入值。

于 2009-11-13T20:09:49.180 回答
1

是的,需要内存屏障才能获得最新的值。

如果内存屏障不存在,那么线程 X 可以从它自己的缓存行读取 m_bar 的值,而该值尚未写回主内存(更改已在线程 Y 本地进行)。您可以通过将变量声明为 volatile 来实现相同的效果:

volatile修饰符通常用于被多个线程访问而不使用lock语句序列化访问的字段。使用 volatile 修饰符可确保一个线程检索另一个线程写入的最新值。

关于这个问题的一个很好的条目(可能是最好的)是 Joe Duffy 的这篇文章:易失性读写,以及及时性

于 2009-11-13T20:10:26.193 回答
0

内存屏障实际上与 wat 锁定的作用相同,保证该字段将在进入锁时从内存中获取其最新值,并在退出锁之前写入内存。
使用 volatile 关键字也可以确保字段的值始终被读取或写入内存并且永远不会通过首先读取或写入 cpu 的缓存来优化。
除非原始整数类型和引用类型 DateTime 不能缓存在 CPU 寄存器中,否则不需要(也不能)用 volatile 关键字声明。

于 2009-11-13T23:21:24.537 回答
-1

这实际上无关紧要,因为在 32 位架构上,在这种情况下可能会被撕裂

于 2009-11-14T20:48:31.153 回答