Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is `volatile` required for double-checked locking in Java but not C#?

It's very well known among Java programmers that in order for double-checked locking to function correctly, the variable must be declared volatile, and synchronizing the initialization of the object is not enough.

The awareness is probably mostly because the semantics of the volatile keyword were changed in 1.5 to include a "happens before" relationship, at least in part to make double-checked locking safe; from what I understand, the "happens-before" relationship means writing to a volatile variable causes all cached variables in the thread to be written to main memory, and after reading from a volatile variable, all cached variables are considered stale, and must be re-read from main memory, so that everything written before a write to a volatile variable is guaranteed to "happen before" a later read from that variable.

Stack Overflow seems to believe that, for C#, volatile is unnecessary for double-checked locking (despite noting concerns that this may be specific to certain CPUs or to Microsoft's implementation), while also believing that the semantics of Java's synchronized statement are exactly the same as C#'s lock statement, which suggests that the same issues identified in Java would also exist for C#, unless some other major difference exists in the semantics of double-checked locking between the two languages.

So...which is correct? Is double-checked locking in C# actually less dangerous than in Java? If so, what language semantics differ to make that the case?

If not, what specifically can go wrong without volatile? Does the semantics of volatile in C# establish a "happens-before" relationship like Java, so that double-checked locking is as safe in C# with volatile as it is in Java since 1.5?

like image 567
Theodore Murdock Avatar asked Oct 20 '22 10:10

Theodore Murdock


1 Answers

From MSDN: "The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time. Fields that are declared volatile are not subject to compiler optimizations that assume access by a single thread. This ensures that the most up-to-date value is present in the field at all times."

So, volatile is only useful if you are changing the variable's value from multiple threads. If you lock() the code areas which acess shared resources with same locking object you are guaranteed that only one thread can access those code areas simultaneously, then volatile is not needed unless you are modifying the locking object (which is a really bad idea).

like image 50
Gusman Avatar answered Oct 23 '22 01:10

Gusman