Mutex and Channels
Synchronization Mechanisms in Go
Go provides two primary mechanisms for managing concurrent state: Mutexes and Channels. Each approach offers unique advantages for different synchronization scenarios.
Mutex (Mutual Exclusion)
Understanding Mutex
A mutex provides a locking mechanism to ensure that only one goroutine can access a critical section of code at a time.
graph TD
A[Goroutine 1] -->|Acquire Lock| B[Critical Section]
C[Goroutine 2] -->|Wait for Lock| B
Mutex Example
package main
import (
"fmt"
"sync"
)
type SafeCounter struct {
mu sync.Mutex
value int
}
func (c *SafeCounter) Increment() {
c.mu.Lock()
defer c.mu.Unlock()
c.value++
}
func (c *SafeCounter) Value() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.value
}
func main() {
counter := &SafeCounter{}
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
counter.Increment()
}()
}
wg.Wait()
fmt.Println("Final counter value:", counter.Value())
}
Channels for Communication
Channel Types and Operations
Channel Type |
Description |
Use Case |
Unbuffered Channels |
Synchronous communication |
Strict coordination |
Buffered Channels |
Asynchronous communication |
Decoupled processing |
Directional Channels |
Send-only or receive-only |
Controlled access |
Channel Example
package main
import (
"fmt"
"time"
)
func worker(id int, jobs <-chan int, results chan<- int) {
for job := range jobs {
fmt.Printf("Worker %d processing job %d\n", id, job)
time.Sleep(time.Second)
results <- job * 2
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs)
for a := 1; a <= 5; a++ {
<-results
}
}
Choosing Between Mutex and Channels
Comparison
Scenario |
Mutex |
Channels |
Shared State Modification |
Preferred |
Less Ideal |
Complex Communication |
Less Suitable |
Preferred |
Simple Synchronization |
Good |
Possible |
Best Practices
- Use mutexes for protecting shared state
- Use channels for communication between goroutines
- Avoid sharing memory, instead communicate
At LabEx, we recommend understanding both mechanisms to write efficient concurrent Go programs.