package main
import (
"fmt"
"sync"
)
// without using mutex the following error can happen: "fatal error: concurrent map writes" while changing the map in multiple goroutines
type Storage struct {
sync.Mutex
storage map[string]int // map is not threade-safe
}
func (s *Storage) Increment(name string) {
s.Lock() // lock the mutex before accessing counters
defer s.Unlock() // unlock the mutex at the end of the function using a defer statement
s.storage[name]++
}
func (s *Storage) Decrement(name string) {
s.Lock()
defer s.Unlock()
s.storage[name]--
}
func main() {
s := &Storage{
storage: make(map[string]int),
}
wg := sync.WaitGroup{}
wg.Add(5)
// increment a named counter in a loop
increment := func(name string, count uint) {
for i := 0; i < int(count); i++ {
s.Increment(name)
}
wg.Done()
}
// decrement a named counter in a loop
decrement := func(name string, count uint) {
for i := 0; i < int(count); i++ {
s.Decrement(name)
}
wg.Done()
}
// run 5 goroutines concurrently
go increment("a", 1000)
go decrement("a", 500)
go increment("b", 1000)
go increment("b", 1000)
go decrement("b", 1500)
wg.Wait() // wait for the goroutines to finish
fmt.Println(s.storage)
}
// $ go run main.go
// map[a:500 b:500]
// without mutex the following error can happen
// $ go run main.go
// fatal error: concurrent map writes
Mutexes can be used to safely access data across multiple goroutines.This example shows how to use mutexes in Go to change a map concurrently and safely.