volatile字段:如何真正获取该字段最后写入的值?考虑以下示例:privateintsharedState=0;privatevoidFirstThread(){Volatile.Write(refsharedState,1);}privatevoidSecondThread(){intsharedStateSnapshot=Volatile.Read(refsharedState);Console.WriteLine(sharedStateSnapshot);直到最近,我的印象是只要FirstThread()确实在SecondThread()之前执行,程序就不能输出除1之外的任何内容。但是,我目前的理解是:或者,换句话说:如果我的理解是正确的,那么如果FirstThread()的写入尚未释放,则没有什么可以阻止sharedState变得“陈旧”。如果这是真的,我们如何才能真正确保(假设是最弱的处理器内存模型,如ARM或Alpha)程序将始终打印1?(或者我的心智模型在某个地方犯了错误?)你的理解是正确的,你不能确定一个程序总是会使用这些技术打印1。为确保程序打印1,假设线程2在第一个线程之后运行,每个线程需要两个栅栏。实现这一点的最简单方法是使用lock关键字:privateintsharedState=0;私有只读对象储物柜=新对象();privatevoidFirstThread(){lock(locker){sharedState=1;}}privatevoidSecondThread(){intsharedStateSnapshot;锁(储物柜){sharedStateSnapshot=sharedState;}Console.WriteLine(sharedStateSnapshot);}我想引用EricLippert的话:坦率地说,我不鼓励你做一个不稳定的领域。可变字段表明您正在做一些非常疯狂的事情:您试图在两个不同的线程上读取和写入相同的值,而没有锁定到位。这同样适用于对Volatile.Read和Volatile.Write的调用。事实上,它们甚至比volatile字段更糟糕,因为它们需要您手动执行volatile修饰符自动执行的操作。你是对的,不能保证所有处理者都会立即看到发布存储。Volatile.Read和Volatile.Write为您提供获取/释放语义,但没有即时保证。不过,volatile修饰符似乎也有同样的作用。编译器将发出OpCodes.VolatileIL指令,抖动将告诉处理器不要将变量存储在任何寄存器上(参见HansPassant的回答)。但为什么你立即需要它?如果您的SecondThread在实际写入值之前运行了几毫秒怎么办?由于调度是不确定的,程序的正确性无论如何不应依赖于这种“即时性”。直到最近,我的印象是只要FirstThread()在SecondThread()之前执行,程序就不能输出除1之外的任何内容。这个印象是错误的,因为你继续解释自己。Volatile.Read只是在其目标上发出读取操作,然后是内存屏障;内存屏障阻止了对执行当前线程的处理器的操作重新排序,但这在这里没有用,因为没有操作的重新排序(每个线程中只有单个读取或写入)。线程中的竞争条件意味着即使不重新排序保证适用于跨处理器,它也只是意味着无法保留的操作顺序将被保留。如果我的理解是正确的,那么如果FirstThread()中的写入尚未释放,则没有什么可以阻止sharedState变得“陈旧”。这是正确的。从本质上讲,您使用的工具旨在帮助弱内存模型应对竞争条件可能导致的问题。该工具不会帮助您,因为那不是它的作用。如果这是真的,我们如何才能真正确保(假设是最弱的处理器内存模型,如ARM或Alpha)程序将始终打印1?(或者我的心智模型在某个地方犯了错误?)再说一遍:内存模型不是问题所在。为确保您的程序始终打印1,您需要做两件事:提供显式线程同步,保证写入发生在读取之前(在最简单的情况下,SecondThread可以用在FirstThread中以指示FirstThread的标志在其上使用自旋锁).确保SecondThread不会读取过时的值。您可以通过将sharedState标记为volatile轻松地做到这一点——虽然这个关键字理所当然地得到了很多绒毛,但它是专门为这个用例设计的。因此,在最简单的情况下,例如:privatevolatileintsharedState=0;privatevolatileboolspinLock=false;privatevoidFirstThread(){sharedState=1;//确保在共享状态写入后释放锁!挥发性.Write(refspinLock,true);}privatevoidSecondThread(){SpinWait.SpinUntil(()=>spinLock);Console.WriteLine(sharedState);}假设这两个字段没有其他写入,程序保证只输出1。以上是C#学习教程:VolatileFields:Howtoactuallygetthelatestwrittenvalueofthefield?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
