How to make reading this instance primitive thread-safe without locking?

女生的网名这么多〃 提交于 2019-12-06 13:18:40

OK, I believe I found the answer and my concern is vindicated!

The code happens to be thread-safe on x86 and AMD64 because they invalidate a CPUs cache when the variable is written to causing subsequent reads to read the variable from memory. to quote Shafqay Ahmed quoting Jeffrey Richter:

Since two processors can have different caches, which are copies of the ram, they can have different values. In x86 and x64 processors (according to Jeffrey’s book) are designed to sync the caches of different processors so we may not see the problem.

Incidentally using lock and Interlocked flushes the variable from cache, so using lock when reading the property would have been safe. From http://blogs.msdn.com/b/ericlippert/archive/2011/06/16/atomicity-volatility-and-immutability-are-different-part-three.aspx:

Locks guarantee that memory read or modified inside the lock is observed to be consistent, locks guarantee that only one thread accesses a given hunk of memory at a time, and so on.

However there is no guarantee in the CLR specification given when reading a value updated by another thread (without using locking synchronization constructs) will be the most recent. Indeed on ARM I could well get an old value using ThreadSafe class as it is, from http://msdn.microsoft.com/en-us/magazine/jj553518.aspx:

If your code relies on lock-free algorithms that depend on the implementation of the x86 CLR (rather than the ECMA CLR specification), you’ll want to add the volatile keyword to relevant variables as appropriate. Once you’ve marked shared state as volatile, the CLR will take care of everything for you. If you’re like most developers, you’re ready to run on ARM because you’ve already used locks to protect your shared data, properly marked volatile variables and tested your app on ARM.

So it seems the answer is I can use a lock when reading or make my field volatile, though perhaps I should use lock and try reduce the number of calls, as a man who worked on the compiler says:

The number of situations in which a lock is too slow is very small, and the probability that you are going to get the code wrong because you don't understand the exact memory model is very large. I don't attempt to write any low-lock code except for the most trivial usages of Interlocked operations. I leave the usage of "volatile" to real experts.

I'm not certain what you mean by "most up to date value". You can use locks to ensure that you don't read Value at the same time it is being written to, which may yield some oddities, but if you read it then write to it, you won't have the most up to date value.

To handle the oddities I referred to, you can use locks as you have done. But you seem to desire a different solution. If you don't want to lock the read, but you want to ensure that the write is atomic such that the read won't return an odd number or some other messy thing when doing a read during a multithreaded write, then I would recommend using the Interlocked class.

Simply:

Interlocked.Add(ref value, 47);

More Interlocked functions can be found at http://msdn.microsoft.com/en-us/library/system.threading.interlocked(v=vs.110).aspx

These functions are great when working with primitives. With more complicated objects, other solutions like ReaderWriterLockSlim and others will be needed.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!