Atomic operations in Go provide a way to perform thread-safe operations on shared variables without using locks. These operations are essential for concurrent programming and ensuring data integrity in multi-threaded environments.
Atomic operations are indivisible and uninterruptible actions that complete in a single step from the perspective of other Go Goroutines. They are crucial for managing shared resources in concurrent programs.
Go provides atomic operations through the sync/atomic
package. This package offers functions for performing atomic operations on integers and pointers.
atomic.AddInt64()
: Atomically adds a value to an int64atomic.LoadInt64()
: Atomically loads an int64 valueatomic.StoreInt64()
: Atomically stores an int64 valueatomic.CompareAndSwapInt64()
: Atomically compares and swaps an int64 valueHere's a simple example of using atomic operations to implement a thread-safe counter:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var counter int64
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
atomic.AddInt64(&counter, 1)
wg.Done()
}()
}
wg.Wait()
fmt.Println("Counter:", atomic.LoadInt64(&counter))
}
In this example, we use atomic.AddInt64()
to increment the counter safely across multiple goroutines. The atomic.LoadInt64()
function is used to read the final value.
The Compare and Swap (CAS) operation is a powerful atomic operation that allows you to update a value only if it matches an expected value. Here's an example:
func incrementIfEven(addr *int64) bool {
for {
old := atomic.LoadInt64(addr)
if old%2 != 0 {
return false
}
if atomic.CompareAndSwapInt64(addr, old, old+1) {
return true
}
}
}
This function increments a value only if it's even, using atomic.CompareAndSwapInt64()
to ensure thread-safety.
Atomic operations in Go provide a powerful tool for managing shared state in concurrent programs. They offer better performance than mutexes for simple operations but require careful use to ensure correctness. As you delve deeper into Go concurrency, understanding atomic operations becomes crucial for writing efficient and safe concurrent code.