我读过很多相互矛盾的信息(msdn,SO等)。关于易失性和VoletileRead (ReadAcquireFence)。
我理解那些内存访问重新排序限制的含义--我仍然完全不明白的是新鲜度保证--这对我来说非常重要。
(...)这可确保字段中始终显示最新的值。
msdn doc for volatile fields提到:
对易失性字段的读取称为易失性读取。易失性读取具有“获取语义”;也就是说,它保证发生在指令序列中它之后发生的任何对内存的引用之前。
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 doc内存屏障防止重新排序。然而,这似乎对新鲜度没有任何影响-对吗?
那么如何才能得到保鲜度呢?标记字段易失性与使用VolatileRead和VolatileWrite语义访问它有什么不同?我目前正在做我的性能关键代码的后期工作,需要保证新鲜度,但是读者有时会得到陈旧的价值。我想知道,如果将状态标记为易失性,情况是否会有所不同。
EDIT1:
我想要实现的是--确保读取器线程将获得尽可能多的共享变量(由多个写入器编写)的最新值-理想情况下,不会超过上下文切换或其他可能延迟状态直接写入的操作的成本。
如果易失性或更高级别的构造(例如锁)有这个保证(它们有吗?)那么他们如何做到这一点呢?
EDIT2:
非常简洁的问题应该是-如何保证在读取过程中获得尽可能新的值??理想情况下不需要锁定(因为不需要独占访问,并且存在高争用的可能性)。
根据我在这里学到的东西,我想知道这是否可能是解决方案(解决(?)行用注释标记):
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调用是为了确保读取和写入都被完全隔离(与锁定代码相同-如此处的“内存障碍和锁定”部分所示)。
看起来是正确的还是有缺陷的?
EDIT3:
多亏了这里非常有趣的讨论,我学到了相当多的东西,实际上我能够提炼出关于这个主题的简单而明确的问题。它与原来的版本有很大的不同,所以我在这里发布了一个新版本:
https://stackoverflow.com/questions/24677773
复制相似问题