How to Fix fatal error: concurrent map read and map write in Go

Go raises the “fatal error: concurrent map read and map write” error when multiple goroutines are trying to read and write to the same map simultaneously. This can lead to data races and undefined behavior, so Go’s runtime detects this situation and raises a panic.

To fix the fatal error: concurrent map read and map write error, synchronize access to the map using sync.Mutex or sync.Map.

Method 1: Use a sync.Mutex or sync.RWMutex

You can use a mutex to ensure that only one goroutine can access the map. This is a common approach to synchronizing access to shared data structures.

Example

package main

import (
  "fmt"
  "sync"
)

type SafeMap struct {
  mu sync.RWMutex
  items map[string]int
}

func (sm *SafeMap) Set(key string, value int) {
  sm.mu.Lock()
  defer sm.mu.Unlock()
  sm.items[key] = value
}

func (sm *SafeMap) Get(key string) (int, bool) {
  sm.mu.RLock()
  defer sm.mu.RUnlock()
  value, ok := sm.items[key]
  return value, ok
}

func main() {
  sm := &SafeMap{
  items: make(map[string]int),
}

 // Use the Set and Get methods to safely access the map
 sm.Set("one", 1)
 value, ok := sm.Get("one")

 if ok {
   fmt.Println("Value:", value)
 } else {
   fmt.Println("Key not found")
 }
}

Output

Value: 1

In this code example, we created a SafeMap struct that wraps a map and a sync.RWMutex.

The Set() and Get() methods lock the mutex before accessing the map and unlock it afterward, ensuring that only one goroutine can read or write to the map at a time.

Method 2: Use sync.Map

Go provides a sync.Map type specifically designed for concurrent access. It is a concurrent-safe map implementation that can be used without explicit locking.

Example

package main

import (
  "fmt"
  "sync"
)

func main() {
 var sm sync.Map

 // Store and Load values using the sync.Map methods
 sm.Store("one", 1)
 value, ok := sm.Load("one")

 if ok {
   fmt.Println("Value:", value)
 } else {
   fmt.Println("Key not found")
 }
}

Output

Value: 1

In this code example, we used the sync.Map type instead of a regular map.

The Store() and Load() methods of sync.Map are safe for concurrent use.

Both methods can fix the “concurrent map read and map write” error, but you should choose the one that best fits your use case. If your application has a lot of contention (many goroutines frequently access the map), use a sync.Map might provide better performance.

However, if contention is low, a regular map with a sync.Mutex or sync.RWMutex may suffice.

That’s it.