volatile member variable with Interlocked

  • Thread starter Mark Salsbery [MVP]
  • Start date
M

Mark Salsbery [MVP]

I have an member variable (int) that is accessed by multiple threads using
Interlocked.Increment(), Interlocked.Decrement(), and read directly.

Using volatile gives me "CS0420: a reference to a volatile field will not be
treated as volatile" warnings when using the Interlocked functions, which I
can easily disable with "#pragma warning disable 420".

Should this variable be marked volatile? Is volatile necessary in this
case?

Thanks!
Mark
 
J

Jeroen Mostert

Mark said:
I have an member variable (int) that is accessed by multiple threads
using Interlocked.Increment(), Interlocked.Decrement(), and read directly.

Using volatile gives me "CS0420: a reference to a volatile field will
not be treated as volatile" warnings when using the Interlocked
functions, which I can easily disable with "#pragma warning disable 420".
Annoying, isn't it? They should have built in an exception for the
Interlocked functions.

One way to avoid it without disabling it is to remove the volatile qualifier
and explicitly use Thread.VolatileRead() instead. This might be less
intuitive and easier to get wrong than relying on volatile, though. Then
again, just using interlocked fields is less intuitive than using monitors. :)
Should this variable be marked volatile? Is volatile necessary in this
case?
In all likelihood, yes. You've got atomic reads and writes covered, but if
you don't use volatile, the compiler is free to "optimize" access in the
threads that read the value. This means there could be an arbitrary delay
between the interlocked updates and the reader(s) seeing them (technically
it's even legal if things are optimized in such a way that the readers
*never* see the updates, but I've never seen the compiler produce code like
that).
 
M

Mark Salsbery [MVP]

Jeroen Mostert said:
One way to avoid it without disabling it is to remove the volatile
qualifier and explicitly use Thread.VolatileRead() instead.


Thread.VolatileRead() ! That's what I was looking for - I hadn't seen that
before.

Sure, I could use lock/Monitor but it's a relatively heavyweight solution
for incrementing/decrementing an integer atomically.

I realize this has been discussed many times here before - I guess I used
the wrong search keywords last time.

From everything I can find, it seems Interlocked accesses the variable with
volatile semantics - I was just missing a way to read the variable the same
way.

Thank you Jeroen!

Cheers,
Mark
 
J

Jeroen Mostert

Mark said:
Sure, I could use lock/Monitor but it's a relatively heavyweight
solution for incrementing/decrementing an integer atomically.
Look at it the other way around: *not* using monitors is an optimization,
and like all optimizations probably not something you should use from the
get-go until you can show that you need it.

Multithreading is hard enough, once you abandon monitors and use primitives
directly it *really* gets hard. Before you know it you're getting a headache
reading twelve-page threads on memory models and wondering whether this read
over here really is safe on an Itanium.

That's my experience, at least -- my respect goes out to all the people who
have no trouble applying these things in their daily job. I'm holding out
for better library support. :)
 
J

Jon Skeet [C# MVP]

Look at it the other way around: *not* using monitors is an optimization,
and like all optimizations probably not something you should use from the
get-go until you can show that you need it.

Multithreading is hard enough, once you abandon monitors and use primitives
directly it *really* gets hard. Before you know it you're getting a headache
reading twelve-page threads on memory models and wondering whether this read
over here really is safe on an Itanium.

That's my experience, at least -- my respect goes out to all the people who
have no trouble applying these things in their daily job. I'm holding out
for better library support. :)

That's pretty much exactly what I'd say, too.

Another way of doing an atomic read is with
int y = Interlocked.CompareExchange(ref x, 0, 0)
which will basically read and conditionally exchange with the same
value.

Jon
 
M

Mark Salsbery [MVP]

Jon Skeet said:
Another way of doing an atomic read is with
int y = Interlocked.CompareExchange(ref x, 0, 0)
which will basically read and conditionally exchange with the same
value.


Thanks Jon.

Mark
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top