I am using the example described here https://jenkov.com/tutorials/java-concurrency/false-sharing.html where we have the following class:
public class Counter {
public volatile long count1 = 0;
public volatile long count2 = 0;
}
and two threads are each updating the variables count1 and count2 at the same time. Because count1 and count2 are in the same cache line, each time a thread updates one of the variables, the other thread needs to refresh the cache line.
My question is regarding the volatile keyword. The way volatile is usually presented is that when a thread A updates a volatile variable x, and then another thread B reads x, that other thread B is guaranteed to see the updated value of x. But here volatile is used on two different variables. So another property of volatile would be that when a thread A updates a volatile variable, if another thread B then reads any other (also volatile?) variable from the same cache line, then that other thread B needs to refresh the whole cache line?
Both variables need to be volatile. Caches on modern CPUs are always coherent. So it doesn't matter if a cache line is falsely shared or not since the cache ensures coherence. It is the compiler that can still mess things up.
If there is data race, then the JMM allows for any written value to be seen the read is in data race with (*). So imagine the following example:
class FalseSharing{
int a;
volatile int b;
}
The FalseSharing instance is shared between multiple threads and one thread does the following:
while(shared.a==0){
print(shared.b);<== triggers the false sharing
}
And another thread at some point calls 'shared.a=1'. Because there is a data race on 'a', the compiler can rewrite the code to:
if(shared.a==0){
while(true){
print(shared.b);
}
}
This is legal since the JMM mandates that the possible read values of 'a' are {0,1}. And JVM is allowed to produce executions that produce a subset; in this case {0}.
After this code transformation, it is clear that it doesn't matter if 'a' is piggybacking on a falsely shared cache line.
(*) Happens-before consistent is the JMM's solution to prevent undefined behavior in case of a data race. It states that a read needs to see the most recent write before it is in the happens-before order, or a write it is in data race with.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With