volatile with release/acquire semantics
Asked Answered
H

2

8

Since Java 5, the volatile keyword has release/acquire semantics to make side-effects visible to other threads (including assignments to non-volatile variables!). Take these two variables, for example:

int i;
volatile int v;

Note that i is a regular, non-volatile variable. Imagine thread 1 executing the following statements:

i = 42;
v = 0;

At some later point in time, thread 2 executes the following statements:

int some_local_variable = v;
print(i);

According to the Java memory model, the write of v in thread 1 followed by the read of v in thread 2 ensures that thread 2 sees the write to i executed in thread 1, so the value 42 is printed.

My question is: does volatile have the same release/acquire semantics in C#?

Hefter answered 29/6, 2011 at 19:53 Comment(1)
Not exactly; see blogs.msdn.com/b/ericlippert/archive/2011/06/16/…Supersede
U
16

The semantics of "volatile" in C# are defined in sections 7.10 and 14.5.4 of the C# 6.0 specification. Rather than reproduce them here, I encourage you to look it up in the spec, and then decide that it is too complicated and dangerous to use "volatile", and go back to using locks. That's what I always do.

See "7.10 Execution order" and "14.5.4 Volatile fields" in the C# 6.0 specification.


In the C# 5.0 specification, see "3.10 Execution Order" and "10.5.3 Volatile Fields"

Urinate answered 29/6, 2011 at 20:1 Comment(4)
Trying to shy away C++ programmers from details that are "complicated and dangerous" is probably going to have the opposite effect ;)Hefter
@Fred So you're just interested in volatile because it is complicated and dangerous?Mongolia
@David: I simply don't like imprecise knowledge, and my impression is that volatile is one of the most misunderstood keyword ever. I want to know how stuff works, that's all :)Hefter
@Fred I like to know how stuff works but I don't feel the need to learn stuff for the sake of it. Perhaps I'm too old for that!Mongolia
I
7

Well, I believe it ensures that if some_local_variable is read as 0 (due to the write to v), i will be read as 42.

The tricky part is "at some later point in time". While commonly volatility is talked about in terms of "flushing" writes, that's not how it's actually defined in the spec (either Java or C#).

From the C# 4 language spec, section 10.5.3:

For non-volatile fields, optimization techniques that reorder instructions can lead to unexpected and unpredictable results in multi-threaded programs that access fields without synchronization such as that provided by the lock-statement (§8.12). These optimizations can be performed by the compiler, by the run-time system, or by hardware. For volatile fields, such reordering optimizations are restricted:

  • A read of a volatile field is called a volatile read. A volatile read has “acquire semantics”; that is, it is guaranteed to occur prior to any references to memory that occur after it in the instruction sequence.
  • A write of a volatile field is called a volatile write. A volatile write has “release semantics”; that is, it is guaranteed to happen after any memory references prior to the write instruction in the instruction sequence.

There's then an example which is quite similar to yours, but conditional on the value read from the volatile variable.

And like Eric, I'd strongly avoid relying on volatile myself. It's hard to reason about, and best left to the Joe Duffy/Stephen Toubs of the world.

Iz answered 29/6, 2011 at 20:0 Comment(3)
Could you be more specific what you mean with respect to the "flushing" writes in Java? Are you implying that my code does not even work in Java?Hefter
@Fred Well if we believe Jon's small quote, it'd seem like C# does guarantee release semantics for writes and acquire semantics for reads which would mean that yes the example would work fine in both java and C#.. and now you still have to go and read the important sections to be sure to not miss some corner case. And while I can totally understand why avoiding volatile (and semaphores and all other low level threading stuff at that) is in general no bad idea, I also hate to have holes in my knowledge - and just because you know how to use volatile, doesn't mean you have to!Fanti
@Fred: The problem is you haven't defined what you mean by "some time later". What you can guarantee is that if thread 2 sees the write to the volatile variable, then it will also see the write to the non-volatile variable.Iz

© 2022 - 2024 — McMap. All rights reserved.