Can anybody show the example where usage of such atomic operations needed. I don't understand a differenece between
import "sync/atomic"
...
var sharedA int64
var sharedB *int64
...
// concurent code
tmpVarA := sharedA
tmpVarB := *sharedB
// and
tmpVarA := atomic.LoadInt64(&sharedA)
tmpVarB := atomic.LoadInt64(sharedB)
It's not documented in the package at all, but normally atomic loads and stores of normal values are there not for atomicity because the CPU operations are already atomic, but for ordering. The language specification or CPU instruction documentation gives you certain guarantees about in which order one CPU stores will be seen by another CPU if you use the atomic operations. Most modern CPUs have no such guarantees if you don't use the proper (expensive) instructions for it.
So in your example (I assume, since the package isn't documented), if the shared variables have been written by a goroutine first to sharedA
, then sharedB
, when reading then without atomic operations you might see the changed value of sharedB
and still the old value of sharedA
. It's different on different CPU families if the stores or loads need to perform extra magic to get the ordering right, so usually languages make you use atomic functions for both stores and loads and then the compiler/library knows what your actual CPU needs.
Of course, the package doesn't document any of this, so in practice there is no difference because we don't know what the package actually guarantees. So for all practical purposes it's useless.
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