The sync/atomic
package in Go provides low-level atomic memory primitives useful for implementing synchronisation
algorithms.
- Introduction to Atomic Operations
- Atomic Variables
- Atomic Functions
- Use Cases
- Common Pitfalls
- Best Practices
- Resources
Atomic operations provide a way to read or modify values in memory in a way that ensures that no other operations can occur concurrently that would see a partially completed state or interfere with the operation.
import "sync/atomic"
counter := atomic.Int64{}
// Increment counter atomically
value := atomic.AddInt64(&counter, 1)
// Atomically load the value of counter
value := atomic.LoadInt64(&counter)
// Atomically store a value in counter
atomic.StoreInt64(&counter, 42)
// Atomically compare counter to old and if they are equal set counter to new
swapped := atomic.CompareAndSwapInt64(&counter, old, new)
See package
Atomic operations are used when you need to ensure that operations on memory are completed without interruption, such as when implementing counters, flags, and other synchronisation primitives.
- Mixing atomic operations with regular, non-atomic operations on the same variable can lead to data races and unpredictable behavior.
var counter int64 // shared variable
// Incorrect Usage: Mixing atomic and non-atomic operations
func incrementNonAtomic() {
counter++
}
func incrementAtomic() {
atomic.AddInt64(&counter, 1)
}
- Avoid mixing atomic and non-atomic operations on the same variable.
- Utilize the specialized types in the sync/atomic package over general integer types for atomic operations to ensure type safety, platform independence, and clearer, less error-prone code.
var counterInt int
var counterInt64 atomic.Int64
// Avoid increment using int variable
atomic.AddInt64((*int64)(&counterInt), 1)
// Instead increment using atomic.Int64 variable
counterInt64.Add(1)