sync/atomic introduction
When we want to modify a variable concurrently, in addition to using the official onemutex, you can also use the atomic operation of the sync/atomic package, which can ensure that the variables are not affected by other coroutines during reading or modification.
atomic packageAtomic operationIt is implemented through CPU instructions, that is, at the hardware level, with good performance and does not need to record many states like mutex. Of course, mutex is not only a concurrent control of variables, but more a concurrent control of code blocks. The two have different focuses.
sync/atomic operation
The atomic package has several atomic operations, mainly Add, CompareAndSwap, Load, Store, and Swap.
Add
Atomic's Add is atomically added to int and uint:
func AddInt32(addr *int32, delta int32) (new int32) func AddUint32(addr *uint32, delta uint32) (new uint32) func AddInt64(addr *int64, delta int64) (new int64) func AddUint64(addr *uint64, delta uint64) (new uint64) func AddUintptr(addr *uintptr, delta uintptr) (new uintptr)
CompareAndSwap
The comparison and exchange method realizes a function similar to optimistic locking. Only when the original value is the same as the incoming old value will it be modified:
func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool) func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool) func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool) func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool) func CompareAndSwapUintptr(addr *uintptr, old, new uintptr) (swapped bool) func CompareAndSwapPointer(addr *, old, new ) (swapped bool)
It should be noted that CompareAndSwap may generateABAA phenomenon occurs. That is, the original value is A, which is later modified B, and then modified to A. In this case, CompareAndSwap rules are also compliant, even if they have been modified in the middle.
Load
The Load method is to prevent other coroutines from launching modification actions during the reading process, which affects the reading result. It is often used forConfiguration ItemsThe entire read.
func LoadInt32(addr *int32) (val int32) func LoadInt64(addr *int64) (val int64) func LoadUint32(addr *uint32) (val uint32) func LoadUint64(addr *uint64) (val uint64) func LoadUintptr(addr *uintptr) (val uintptr) func LoadPointer(addr *) (val )
Store
If there is atomic reading, there is atomic modification value. The Add mentioned above is only applicable to the addition and decrease of int and uint types, and there are no other types of modifications. The Sotre method achieves modifications to other types by pointer atomic modification.
func StoreInt32(addr *int32, val int32) func StoreInt64(addr *int64, val int64) func StoreUint32(addr *uint32, val uint32) func StoreUint64(addr *uint64, val uint64) func StoreUintptr(addr *uintptr, val uintptr) func StorePointer(addr *, val )
Swap
The Swap method implements atomic exchange of values, not only int, uint can be swapped, but also pointers can be swapped.
func SwapInt32(addr *int32, new int32) (old int32) func SwapInt64(addr *int64, new int64) (old int64) func SwapUint32(addr *uint32, new uint32) (old uint32) func SwapUint64(addr *uint64, new uint64) (old uint64) func SwapUintptr(addr *uintptr, new uintptr) (old uintptr) func SwapPointer(addr *, new ) (old )
Summarize
Atomic may not be used in many cases. After all, mutex has better scalability and is more friendly to use. But this does not hinder our pursuit of ultimate performance. Sometimes, details determine performance!
The above is the detailed explanation of the golang atomic operation example. For more information about golang atomic operation, please follow my other related articles!