Concurrency Programming Essentials
Concurrency Programming Essentials
Core Principles
- Keep critical sections pure
- Control critical section granularity
- Reduce execution time in critical sections
- Avoid holding mutexes for long periods
- Use atomic operations instead of mutexes when possible
uint32 is the shortest numeric type that supports atomic operations. You can save space for counters using this type.
Timeout Control
Use the context package to gracefully shut down multiple goroutines with timeouts.
How to implement timeout checks without starting extra goroutines? Use CAS (Compare-And-Swap) operations to check if the state remains original. If it has timed out, the state will change to something else.
A common mistake: using <-time.After() inside for-select loops causes memory leaks. The garbage collector won’t reclaim timers before they fire!
func ProcessChannelMessages(ctx context.Context, in <-chan string, idleCounter prometheus.Counter) {
idleDuration := 5 * time.Minute
idleDelay := time.NewTimer(idleDuration)
// Remember to stop the timer
defer idleDelay.Stop()
for {
// Reset and activate the same timer after expiration
idleDelay.Reset(idleDuration)
select {
case s, ok := <-in:
if !ok {
return
}
// Wait for timer to expire
case <-idleDelay.C:
idleCounter.Inc()
case <-ctx.Done():
return
}
}
}