0
0
GoDebug / FixBeginner · 4 min read

How to Fix Race Condition in Go: Simple Guide

A race condition in Go happens when multiple goroutines access shared data at the same time without proper synchronization. To fix it, use sync.Mutex or channels to control access and ensure only one goroutine modifies the data at a time.
🔍

Why This Happens

A race condition occurs when two or more goroutines try to read and write the same variable at the same time without coordination. This causes unpredictable results because the order of operations is not controlled.

go
package main

import (
	"fmt"
	"time"
)

var counter int

func increment() {
	counter = counter + 1
}

func main() {
	for i := 0; i < 1000; i++ {
		go increment()
	}
	// Wait for goroutines to finish
	time.Sleep(time.Second)
	fmt.Println("Counter:", counter)
}
Output
Counter: 987
🔧

The Fix

Use sync.Mutex to lock the shared variable while a goroutine is updating it. This ensures only one goroutine can change the variable at a time, preventing race conditions.

go
package main

import (
	"fmt"
	"sync"
	"time"
)

var counter int
var mu sync.Mutex

func increment() {
	mu.Lock()
	counter = counter + 1
	mu.Unlock()
}

func main() {
	for i := 0; i < 1000; i++ {
		go increment()
	}
	// Wait for goroutines to finish
	time.Sleep(time.Second)
	fmt.Println("Counter:", counter)
}
Output
Counter: 1000
🛡️

Prevention

Always protect shared data with synchronization tools like sync.Mutex or use channels to communicate between goroutines safely. Use the go run -race command to detect race conditions during development. Writing tests and keeping shared state minimal also helps avoid these bugs.

⚠️

Related Errors

Other concurrency issues include deadlocks, where goroutines wait forever for locks, and livelocks, where goroutines keep changing state without progress. Fix these by careful lock ordering and avoiding holding locks while waiting.

Key Takeaways

Use sync.Mutex or channels to synchronize access to shared data in Go.
Race conditions cause unpredictable results when goroutines access data simultaneously without locks.
Detect race conditions early using the go run -race tool.
Keep shared state minimal and communicate via channels when possible.
Avoid deadlocks by careful lock management and ordering.