Asking this question as a pseudo code, and also targeting both rust and c++ as memory model concepts are ditto
SomeFunc(){
x = counter.load(Ordering::Relaxed) //#1
counter.store(x+1, Ordering::Relaxed) //#2
y = counter.load(Ordering::Relaxed) //#3
}
Question: Imagine SomeFunc is being executed by a thread and between #2 and #3 the thread gets interrupted and now #3 executes on different core, in this case does counter variable get synchronized with the last updated value (core 1) when it runs on another core2 (there is no explicit release/acquire). I suppose the entire cache line+thread local storage gets shelved and loaded when the thread briefly goes to sleep and comes back running on different core?
First of all, it should be noted that atomic instructions add synchronization, and do not remove it.
Would you expect:
unsigned func(unsigned* counter) {
auto x = *counter;
*counter = x + 1;
auto y = *counter;
return y;
}
To return anything else than the original value of *counter
+ 1?
Yet, similarly, the thread could be moved between cores in-between two statements!
The above code executes fine even when the core is moved because the OS takes care during the switch to appropriately synchronize between cores to preserve user-space program order.
So, what happens when using atomics on a single thread?
Well, you add a bit of processing overhead -- more synchronization -- and the OS still takes care during the switch to appropriately synchronize.
Hence the effect is strictly the same.