如何在不加锁的情况下读取这个实例的原始线程安全?下面这个类的问题是在读取myThreadSafe.Value时它可能不会返回最新的值。公共类ThreadSafe{私有int值;publicintValue{get{返回值;}}publicvoidUpdate(){Interlocked.Add(refvalue,47);//更新:使用互锁来避免分散被问问题的注意力。我知道我可以在读写时锁定:publicintValue{get{lock(locker)returnvalue;}}publicvoidUpdate(){lock(locker){value+=47;我一直在关注这种使用锁的模式。但是我正在尝试减少我的代码中的锁的数量(有很多并且它们被频繁调用,我已经分析过并且Montior.Enter()比我认为的花费更多的时间-因为它被调用了很多次)。更新:我现在想知道,如果锁定确实对确保我读取最新值有任何影响,它是否仍然来自机器的CPU缓存之一?(所有的锁都保证是互斥的线程访问)。我认为volatile是答案,MSDN确实说:“这确保最新值始终存在于该字段中”,但我读写然后在其他地方读取CPU指令在使用volatile时仍然可以交换在这种情况下我可以获得以前的myThreadSafe.Value的值,也许我可以接受-只有一次更新。我将始终获得myThreadSafe.Value的最新值的最有效方法是什么?更新:此代码将在CPU架构上编译和运行:使用运行时:我希望所有构建都使用相同的代码!好的,我相信我找到了答案并且我的担忧得到了证实!该代码恰好在x86和AMD64上是线程安全的,因为它们在写入变量时会使CPU缓存无效,从而导致后续读取从内存中读取变量。引用ShafqayAhmed的GeoffreyRichter的话:由于两个处理器可以有不同的缓存,它们是ram的副本,所以它们可以有不同的值。在x86和x64处理器中(根据Jeffrey的书),不同处理器的缓存被设计成同步的,所以我们可能看不到问题。顺便说一下,变量是使用lock和Interlocked从缓存中刷新的,因此在读取属性时使用lock是安全的。来自http://blogs.msdn.com/b/ericlippert/archive/2011/06/16/atomicity-volatility-and-immutability-are-different-part-three.aspx:锁定保证锁内部读取或修改内存是一致,锁定保证一次只有一个线程访问给定的内存块,等等。但是,在读取由另一个线程更新的值(不使用锁同步构造)时,在CLR规范中不保证是最新的。事实上,在ARM上,我可以使用ThreadSafe类来获取旧值,来自http://msdn.microsoft.com/en-us/magazine/jj553518.aspx:如果您的代码依赖于x86CLR(而不是ECMACLR规范)无锁算法的实现,需要根据需要在相关变量上加上volatile关键字。一旦您将共享状态标记为易变的,CLR就会为您处理所有事情。如果您和大多数开发人员一样,您已经准备好在ARM上运行,因为您已经使用锁来保护共享数据,正确标记了volatile变量,并在ARM上测试了您的应用程序。所以看起来答案是我可以在读取时使用锁或使我的字段可变,但也许我应该使用锁并尝试减少调用次数,因为从事编译器工作的人说:锁太慢了很少见,并且由于您不了解确切的内存模型,所以您的代码出错的可能性非常高。除了Interlocked操作的最琐碎的用法外,我不会尝试编写任何低锁代码。我将“volatile”的用法留给真正的专家。我不确定你所说的“最新值”是什么意思。您可以使用锁来确保值在写入时不被读取,这可能会产生一些奇怪的情况,但如果您读取它然后写入它,您将不会拥有最新的值。要处理我提到的奇怪情况,您可以像以前一样使用锁。但是您似乎想要一个不同的解决方案。如果你不想锁定读取,但你想确保写入是原子的,以便在多线程写入期间执行读取时读取不会返回奇数或其他一些混乱的东西,那么我会建议使用Interlocked类。只是:Interlocked.Add(refvalue,47);更多Interlocked函数可以在http://msdn.microsoft.com/en-us/library/system.threading.interlocked(v=vs.110).aspx找到。这些函数在处理原语时非常有用。对于更复杂的对象,将需要其他解决方案,如ReaderWriterLockSlim。以上是C#学习教程:Howtoreadthisinstancerawthreadsafetywithoutlocking?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
