BudiBadu Logo

Samplebadu

Code with Example
BudiBadu Logo
Samplebadu

Go by Example: RWMutex

Go 1.23

Optimize concurrent access with RWMutex (Read-Write Mutex). This example shows how to use `sync.RWMutex` to allow multiple concurrent readers while ensuring exclusive access for writers, a pattern that significantly improves performance for read-heavy workloads.

Code

package main

import (
    "fmt"
    "math/rand"
    "sync"
    "sync/atomic"
    "time"
)

func main() {
    // Map state protected by RWMutex
    var state = make(map[int]int)
    var mutex = &sync.RWMutex{}

    // Track operation counts
    var readOps uint64
    var writeOps uint64

    // Start 100 goroutines to read the state repeatedly
    for r := 0; r < 100; r++ {
        go func() {
            for {
                // RLock() allows multiple simultaneous readers
                // but blocks if a writer has the lock
                mutex.RLock()
                total := 0
                for _, v := range state {
                    total += v
                }
                // RUnlock() releases the read lock
                mutex.RUnlock()
                atomic.AddUint64(&readOps, 1)
                time.Sleep(time.Millisecond)
            }
        }()
    }

    // Start 10 goroutines to write to the state
    for w := 0; w < 10; w++ {
        go func() {
            for {
                key := rand.Intn(5)
                val := rand.Intn(100)
                
                // Lock() requests exclusive access for writing
                // Blocks all other readers and writers
                mutex.Lock()
                state[key] = val
                mutex.Unlock()
                
                atomic.AddUint64(&writeOps, 1)
                time.Sleep(time.Millisecond)
            }
        }()
    }

    // Let the goroutines work for a second
    time.Sleep(time.Second)

    // Report final operation counts
    readOpsFinal := atomic.LoadUint64(&readOps)
    writeOpsFinal := atomic.LoadUint64(&writeOps)
    fmt.Printf("Total operations:\nReads: %d\nWrites: %d\n", 
        readOpsFinal, writeOpsFinal)
}

Explanation

A standard Mutex locks out all other goroutines, whether they want to read or write. However, it's safe for multiple goroutines to read the same memory simultaneously, as long as no one is writing to it. sync.RWMutex (Read-Write Mutex) solves this inefficiency.

RWMutex has two sets of methods: Lock/Unlock for writers (exclusive access) and RLock/RUnlock for readers (shared access). This allows many readers to access the data concurrently, significantly improving performance for read-heavy workloads.

Key differences from Mutex:

  • Use RLock() when you only need to read data
  • Use Lock() when you need to modify data
  • Multiple RLock() calls can happen simultaneously
  • Lock() blocks until all readers are finished

Code Breakdown

13
Initializing a sync.RWMutex. Unlike standard Mutex, this supports separate read and write locks.
25
RLock() acquires a read lock. This will NOT block other readers, allowing high concurrency. It only blocks if a writer currently holds the exclusive Lock().
47
Lock() acquires a write lock. This is exclusive: it waits for all active readers to finish, then blocks all new readers and writers until Unlock() is called.