0
0
GoHow-ToBeginner · 3 min read

How to Use sync.Mutex in Go for Safe Concurrent Access

In Go, use sync.Mutex to protect shared data from concurrent access by locking it with Lock() before accessing and unlocking with Unlock() after. This ensures only one goroutine can access the critical section at a time, preventing race conditions.
📐

Syntax

The sync.Mutex type provides two main methods: Lock() and Unlock(). You create a Mutex variable, then call Lock() before accessing shared data and Unlock() after you're done.

This pattern ensures only one goroutine can enter the critical section at a time.

go
var mu sync.Mutex

mu.Lock()
// critical section: access shared data safely
mu.Unlock()
💻

Example

This example shows two goroutines incrementing a shared counter safely using sync.Mutex. The mutex prevents race conditions by allowing only one goroutine to update the counter at a time.

go
package main

import (
	"fmt"
	"sync"
)

func main() {
	var mu sync.Mutex
	counter := 0
	var wg sync.WaitGroup

	increment := func() {
		defer wg.Done()
		for i := 0; i < 1000; i++ {
			mu.Lock()
			counter++
			mu.Unlock()
		}
	}

	wg.Add(2)
	go increment()
	go increment()

	wg.Wait()
	fmt.Println("Final counter value:", counter)
}
Output
Final counter value: 2000
⚠️

Common Pitfalls

  • Forgetting to Unlock() after Lock() causes deadlocks, freezing your program.
  • Using Mutex incorrectly by locking multiple times without unlocking can also deadlock.
  • Not using a mutex when accessing shared data leads to race conditions and unpredictable results.

Always use defer mu.Unlock() right after mu.Lock() to avoid forgetting to unlock.

go
var mu sync.Mutex

// Wrong: forgetting to unlock causes deadlock
mu.Lock()
// critical section
// mu.Unlock() missing here

// Right way:
mu.Lock()
defer mu.Unlock()
// critical section
📊

Quick Reference

sync.Mutex Cheat Sheet:

  • mu.Lock(): Acquire the lock, blocks if already locked.
  • mu.Unlock(): Release the lock.
  • Use defer mu.Unlock() immediately after locking to ensure unlock.
  • Protect shared variables by locking before access and unlocking after.
  • Mutexes prevent race conditions in concurrent programs.

Key Takeaways

Use sync.Mutex to protect shared data from concurrent access in Go.
Always call Lock() before accessing shared data and Unlock() after.
Use defer Unlock() immediately after Lock() to avoid deadlocks.
Failing to unlock or not using mutex causes deadlocks or race conditions.
Mutexes ensure only one goroutine accesses critical sections at a time.