【发布时间】:2017-01-30 10:11:09
【问题描述】:
假设以下代码(注意这只是示例代码):
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
它说:
在多处理器系统上,易失性写操作可确保 写入内存位置的值立即对所有人可见 处理器。
这就是我想要的。但是,它也指出:
将指定值写入指定字段。在系统上 需要它,插入一个内存屏障,防止处理器 重新排序内存操作如下:如果出现读取或写入 在代码中的这个方法之前,处理器不能在之后移动它 这个方法。
在方法描述中,我不确定这是否是我想要的。
又是我的问题:最后一段代码是否会按照我的意愿执行(使写入立即对其他线程可见)?
【问题讨论】:
-
您肯定想使用
Volatile.Write()而不是volatile。其实Eric Lippert says you should avoidvolatile. -
恕我直言,
Assert.AreEqual(42, safeValue);不知道对Volatile.Write的调用,因此safeValue可能会被缓存。我想Volatile.Read(当你打电话给Assert.AreEqual时)会是首选...... -
Matteo 是正确的 - 您需要在每次写入时使用
Volatile.Write(),在读取时使用Volatile.Read()(线程共享字段)。 -
谢谢大家,我使用了 Volatile.Write 和 Volatile.Read 如你所说。我不能肯定地说它正在工作(它正在工作到现在)。
-
你认为编译器为什么将局部变量作为字段?
标签: c# multithreading volatile