Go by Example

Mutexes

Use sync.Mutex to safely share state across goroutines when atomic operations are not enough.

A mutex lets goroutines take turns in a critical section guarded by the same lock. Use sync.Mutex to coordinate reads and writes that must not happen concurrently.

Lock before changing the counter and unlock when the method returns. Multiple goroutines can safely call Inc.

package main
 
import (
    "fmt"
    "sync"
)
 
type Counter struct {
    mu    sync.Mutex
    value int
}
 
func (c *Counter) Inc() {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.value++
}
 
func (c *Counter) Value() int {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.value
}
 
func main() {
    c := new(Counter)
    var wg sync.WaitGroup
    for i := 0; i < 100; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            c.Inc()
        }()
    }
    wg.Wait()
    fmt.Println(c.Value())
}

In production

Keep the lock next to the state it protects, and unlock with defer immediately after locking. A mutex can protect several fields together when they form one consistent state. Keep locked sections short, and measure contention before changing to a more complex design.

Enjoyed this? Get more software craft delivered to your inbox.