Lock and Instability

I have a variable that I use to represent state. It can be read and written from multiple streams.

I use Interlocked.Exchange and Interlocked.CompareExchange to change it. However, I read it from multiple threads.

I know that volatile can be used to make sure that a variable is not cached locally, but is always read directly from memory.

However, if I set the variable to volatile, then it generates a warning about using volatile and passing using ref to Interlocked.

I want each thread to read the last value of a variable, not some cached version, but I cannot use volatile.

There is Interlocked.Read , but it is designed for 64-bit types and is not available in a compact structure. The documentation for it says that it is not needed for 32-bit types, since they are already performed in one operation.

There are statements on the Internet that you do not need volatility if you use blocking methods for all of your access. However, you cannot read a 32-bit variable using Interlocked methods, so you cannot use Interlocked methods for all of your access.

Is there a way to safely read and write my variable without using a lock?

+59
c # mono
Jul 27 '09 at 5:06
source share
2 answers

You can safely ignore this warning when using the Interlocked.Xxx functions (see this question ), because they always perform mutable operations. So the volatile variable is great for general state. If you want to get rid of the warning at all costs, you can really do a blocked reading using Interlocked.CompareExchange (ref counter, 0, 0) .

Edit: Actually, you need volatile for a state variable only if you are going to write to it directly (i.e. without using Interlocked.Xxx ). As mentioned in jerryjvl , reading a variable updated with a locked (or mutable) operation will use the most recent value.

+30
Jul 27 '09 at 5:13
source share

Blocked operations and volatility should not be used simultaneously. The reason you get a warning is because it (almost?) Always indicates that you misunderstood what you are doing.

Over-simplification and paraphrasing:
volatile indicates that every read should be reread from memory, because there may be other threads updating the variable. When applied to a field that can be read / written atomically by the architecture you work on, this should be all you need to do if you are not using long / ulong, most other types can be read / written atomically.

If the field is not marked as mutable, you can use Interlocked operations to make a similar guarantee, since this leads to a reddening of the cache so that the update is visible to all other processors ... this has the advantage that you impose an overhead on the update rather than reading .

Which of these two approaches works best depends on what exactly you are doing. And this explanation is a gross over-simplification. But from this it should be clear that doing both at the same time is pointless.

+30
Jul 27 '09 at 5:35
source share



All Articles