我已经阅读了许多关于volatile和VolatileRead(ReadAcquireFence)的相互矛盾的信息(来自msdn、SO等等)。
我理解它们的内存访问重新排序限制意义,但我仍然完全困惑于新鲜度保证,这对我非常重要。
(...) 这确保字段中始终存在最新的值。
对volatile字段进行的读取称为volatile读取。volatile读取具有“获取语义”;也就是说,在指令序列中之后发生的任何对内存的引用之前,它都得到了保证。
public static int VolatileRead(ref int address)
{
int ret = address;
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
return ret;
}
根据 msdn MemoryBarrier 文档,内存屏障可以防止重排序,但这似乎对新鲜度没有影响 - 对吗?那么怎样才能获得新鲜度保证呢?标记字段为 volatile 和使用 VolatileRead 和 VolatileWrite 语义访问之间是否有区别?我目前在我的性能关键代码中执行后者以保证新鲜度,但读取器有时会获取旧值。我想知道将状态标记为 volatile 是否会改变情况。
编辑1:
我想要实现的是,读取线程将获得共享变量(由多个写入器编写)最近的值的保证,理想情况下不会比上下文切换或其他可能推迟状态立即写入的操作更旧。
如果 volatile 或更高级别的构造(例如锁定)具有此保证(它们是否具有?),那么它们是如何实现的?
编辑2:
非常简洁的问题应该是 - 我如何获得尽可能新鲜的值保证?理想情况下,不需要锁定(因为不需要独占访问,而且存在高竞争的潜力)。
根据我在这里所学的,我想知道这是否可能是解决方案(已标注带有注释的行):
private SharedState _sharedState;
private SpinLock _spinLock = new SpinLock(false);
public void Update(SharedState newValue)
{
bool lockTaken = false;
_spinLock.Enter(ref lockTaken);
_sharedState = newValue;
if (lockTaken)
{
_spinLock.Exit();
}
}
public SharedState GetFreshSharedState
{
get
{
Thread.MemoryBarrier(); // <---- This is added to give readers freshness guarantee
var value = _sharedState;
Thread.MemoryBarrier();
return value;
}
}
为确保读写操作都被完整的屏障包裹(与锁代码一样),MemoryBarrier调用被添加了进来 - 正如在这里所示的'Memory barriers and locking'部分 - http://www.albahari.com/threading/part4.aspx#_The_volatile_keyword
这看起来正确吗或者有什么缺陷吗?
EDIT3:
感谢这里非常有趣的讨论,我学到了很多东西,实际上我已经能够提炼出关于这个主题的简化明确的问题。 这与原始问题非常不同,所以我在这里更愿意发布一个新的问题:Memory barrier vs Interlocked impact on memory caches coherency timing