假设以下代码(请注意,这只是一个示例代码):
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 写入内存位置的值立即对所有人可见 处理器。
这就是我想要的。但是,它还指出:
将指定的值写入指定的字段。在系统上 需要它,插入一个阻止处理器的内存屏障 重新排序内存操作如下:如果出现读取或写入 在代码中使用此方法之前,处理器无法移动它 这种方法。
在方法描述中,我不确定这是否是我想要的。
我的问题再一次:最后一段代码是否会按照我想要的方式执行(使写入立即对其他线程可见)?
答案 0 :(得分:-1)
在评论中提及 Matteo Umili 和 Matthew Watson 时,您必须在阅读非易失性字段时使用Volatile.Read
。那是因为同步总是2人游戏。
在这种情况下,Volatile.Write
在写入后插入存储释放障碍,Volatile.Read
在读取之前设置加载 - 获取障碍。