Middle+
What synchronization primitives are available in Go? What is the difference between Mutex and RWMutex? When to use atomics?
sobes.tech AI
Answer from AI
In Go, there are several synchronization primitives:
- Mutex (sync.Mutex) — a simple mutex for mutual exclusion, blocks access to a resource for all other goroutines.
- RWMutex (sync.RWMutex) — an extended mutex that allows multiple readers to hold the lock simultaneously, but write access is exclusive.
- WaitGroup — used to wait for a group of goroutines to finish.
- Cond — a condition variable for signaling between goroutines.
- Atomic operations (package sync/atomic) — operations on variables without locks, such as atomic increment of a counter.
Difference between Mutex and RWMutex:
- Mutex completely blocks access, suitable when read and write operations are equally frequent or write operations dominate.
- RWMutex allows multiple readers to read data simultaneously, blocking writers. It is used when reads significantly outnumber writes to improve performance.
When to use atomics:
- For simple operations on primitive types (int, uint64, pointers) when high performance and minimal latency are required.
- When avoiding the overhead of locks.
- For counters, flags, or state indicators.
Example of using Mutex and RWMutex:
var mu sync.Mutex
var rw sync.RWMutex
// Mutex
mu.Lock()
// critical section
mu.Unlock()
// RWMutex
rw.RLock() // for reading
// read data
rw.RUnlock()
rw.Lock() // for writing
// modify data
rw.Unlock()
Example of atomic counter increment:
import "sync/atomic"
var counter int64
atomic.AddInt64(&counter, 1)