# Golang Concurrency #8 - Mutexes

# Introduction

Mutexes solve the problem: "What happens when multiple goroutines access the same variable?"

# The Problem: Race Condition

```go
var counter int

func main() {
    for i := 0; i < 1000; i++ {
        go func() {
            counter++  // Multiple goroutines modifying same variable
        }()
    }

    time.Sleep(time.Second)
    fmt.Println("Counter:", counter)  // Should be 1000, but isn't!
}
```

# Why it breaks

```go
Goroutine 1: Read counter (0) → Add 1 → Write back (1)
Goroutine 2: Read counter (0) → Add 1 → Write back (1)
```

Both read 0 at the same time, both write 1. We lost an increment!

# The Solution: Mutex (Mutual Exclusion)

```go
var counter int
var mutex sync.Mutex

func main() {
    for i := 0; i < 1000; i++ {
        go func() {
            mutex.Lock()    // "I need exclusive access"
            counter++       // Only one goroutine can do this at a time
            mutex.Unlock()  // "I'm done, others can proceed"
        }()
    }

    time.Sleep(time.Second)
    fmt.Println("Counter:", counter)  // Now correctly prints 1000
}
```

# How Mutex works

* `Lock()` - "Wait until no one else is using this, then it's mine"
    
* `Unlock()` - "I'm done, next goroutine can have it"
    
* Only one goroutine can hold the lock at a time
    

# Better pattern with defer

```go
func increment() {
    mutex.Lock()
    defer mutex.Unlock()  // Automatically unlock when function exits

    counter++
    // Even if panic happens, mutex gets unlocked
}
```

# RWMutex (Read/Write Mutex)

```go
var data map[string]int
var rwMutex sync.RWMutex

func readData(key string) int {
    rwMutex.RLock()         // Multiple readers allowed
    defer rwMutex.RUnlock()
    return data[key]
}

func writeData(key string, value int) {
    rwMutex.Lock()          // Exclusive write access
    defer rwMutex.Unlock()
    data[key] = value
}
```

# When to use mutexes

* Protecting shared variables (counters, maps, slices)
    
* When you need to update data structures
    
* When channels would be overkill
    

# Remember

* Always pair `Lock()` with `Unlock()`
    
* Use `defer` to ensure unlocking
    
* Keep critical sections (locked code) small and fast
    
* Prefer channels when possible, use mutexes when necessary
