Golang Atomic
What is Atomic?
In Golang, atomic is a package that provides low-level atomic memory primitives useful for implementing synchronization algorithms. Atomic operations execute in constant time and are implemented in assembly language on supported platforms. They are provided for int32, int64, uint32, uint64, uintptr, unsafe.Pointer, and unsafe.Size values.
Atomic Counter
When incrementing a counter, usually we would do something like this:
Output:
This has the drawback that it cannot be assumed that the counter will be increased by 100. This occurs as a result of numerous goroutines simultaneously accessing the counter. The operating system refers to this phenomenon as a race condition when multiple users simultaneously access the same memory address. Atomic operations are useful in this situation.
To fix this, use the atomic.AddInt64
function to increment the counter by 100.
Output:
Atomic package is used to perform atomic operations on memory addresses. Channels are used to communicate between goroutines. Atomic operations are faster than channels, but channels are more flexible.
Atomic functions
The functions can be of different types. The most common types are int32
, int64
, uint32
, uint64
, uintptr
, unsafe.Pointer
, and unsafe.Size
.
Load and Store
The Load
and Store
functions are used to read and write values to a memory address. The address must be aligned to the size of the value being read or written.
In the above example, the LoadInt64
function returns the value of x
and the StoreInt64
function sets the value of x
to 20.
Swap
The Swap
function is used to swap the value of a memory address with a new value.
In the above example, the SwapInt64
function returns the value of x
before it was swapped. The value of x
is now 20.
CompareAndSwap
The CompareAndSwap
function is used to compare the value of a memory address with a value and swap the value if the comparison is true. The CompareAndSwap
function returns a boolean value indicating whether the swap was successful.
In the above example, the CompareAndSwapInt64
function returns a boolean value indicating whether the swap was successful. The value of x
is now 20.
Add
The Add
function is used to add a value to the value of a memory address.
LoadPointer and StorePointer
The functions LoadPointer
and StorePointer
are used to read and write values to a memory address containing a pointer. LoadPointer
accepts a unsafe.Pointer
value and returns a unsafe.Pointer
. StorePointer
stores a unsafe.Pointer
in the memory address.
In the above example, the LoadPointer
function returns the value of p
and the StorePointer
function sets the value of p
to the memory address of i
which is 1. The LoadPointer
function returns the value of p
which is the memory address of i
and the *(*int64)(p)
returns the value of i
which is 1.
SwapPointer
The SwapPointer
function is used to swap the value of a memory address with a new value.
In the above example, the SwapPointer
function returns the value of p1
before it was swapped. The value of p1
is now p2
and the value of p2
is now p1
. The *(*int64)(p1)
returns the value of p1
which is 2 and the *(*int64)(p2)
returns the value of p2
which is 1.
CompareAndSwapPointer
The CompareAndSwapPointer
function is used to compare the value of a memory address with a value and swap the value if the comparison is true. The CompareAndSwapPointer
function returns a boolean value indicating whether the swap was successful.
In the above example, the CompareAndSwapPointer
function returns a boolean value indicating whether the swap was successful. The value of p1
is now p2
and the value of p2
is now p1
. The *(*int64)(p1)
returns the value of p1
which is 2 and the *(*int64)(p2)
returns the value of p2
which is 1.
Conclusion
To perform atomic operations on memory addresses, the sync/atomic
package is used. The sync/atomic
package includes functions for reading and writing memory addresses, comparing and swapping values, and adding values to memory addresses. The sync/atomic
package also includes functions for reading and writing values to memory addresses with pointers.