在C#中使用Volatile.Write()而不是volatile

时间:2017-01-30 10:11:10

标签: c# multithreading volatile

假设以下代码(请注意,这只是一个示例代码):

public async void UnsafeMethod()
{
  int unsafeValue = 0;

  Task.Run(() => unsafeValue = 42 ); // set unsafeValue to some value
  await Task.Delay(10);              // wait for some time

  Assert.AreEqual(42, unsafeValue);  // check if unsafeValue has the new value
}

(这里假设CPU处于空闲状态并立即执行任务。)

由于任务将在新线程上执行,因此可能由于可能的缓存问题,其他线程可能无法看到unsaveValue的新值。如果我想让更改可见,我将不得不使用volatile并将局部变量设为字段:

private volatile int safeValue = 0;

public async void SafeMethod()
{
  Task.Run(() => safeValue = 42 ); // set safeValue to some value
  await Task.Delay(10);            // wait for some time

  Assert.AreEqual(42, safeValue);  // check if safeValue has the new value
}

(再次假设任务立即执行。)

现在我的问题是,如果以下内容在保留局部变量的同时也会这样做(我知道,编译器会使它成为一个字段......):

public async void AnotherMethod()
{
  int safeValue = 0;

  Task.Run(() => Volatile.Write(ref safeValue, 42); // set safeValue to some value
  await Task.Delay(10);                             // wait for some time

  Assert.AreEqual(42, safeValue);                   // check if safeValue has the new value
}

(任务立即执行。)

文档对我来说并不完全清楚。 https://msdn.microsoft.com/en-us/library/system.threading.volatile(v=vs.110).aspx

它声明:

  

在多处理器系统上,易失性写操作可确保a   写入内存位置的值立即对所有人可见   处理器。

这就是我想要的。但是,它还指出:

  

将指定的值写入指定的字段。在系统上   需要它,插入一个阻止处理器的内存屏障   重新排序内存操作如下:如果出现读取或写入   在代码中使用此方法之前,处理器无法移动它   这种方法。

在方法描述中,我不确定这是否是我想要的。

我的问题再一次:最后一段代码是否会按照我想要的方式执行(使写入立即对其他线程可见)?

1 个答案:

答案 0 :(得分:-1)

在评论中提及 Matteo Umili Matthew Watson 时,您必须在阅读非易失性字段时使用Volatile.Read。那是因为同步总是2人游戏。

在这种情况下,Volatile.Write在写入后插入存储释放障碍,Volatile.Read在读取之前设置加载 - 获取障碍。