Race Condition & Mutex in Go Concurrency
🧠 Race Condition কী? (Simple Definition)
Race Condition ঘটে যখন একাধিক goroutine একই data একসাথে read/write করে, এবং final result unpredictable হয়ে যায়।
অর্থাৎ:
কে আগে চলবে — তার ওপর output বদলে যায়
Result হয় random এবং unreliable
🏃 Real-Life Example (Easy to Imagine)
ধরো:
তোমার এবং তোমার বন্ধুর কাছে একই ব্যাংক অ্যাকাউন্ট
দুজনেই একসাথে টাকা তুলছো
ব্যালেন্স আপডেট হচ্ছে coordination ছাড়া
👉 Result: ভুল balance (ডাটা নষ্ট হয়ে যেতে পারে)
🔴 Race Condition in Go (Real Example)
package main
import (
"fmt"
"sync"
)
var counter = 0
func increment(wg *sync.WaitGroup) {
defer wg.Done()
counter++ // ⚠️ unsafe
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go increment(&wg)
}
wg.Wait()
fmt.Println("Final Counter:", counter)
}
❓ Expected Output
Final Counter: 1000
❗ Actual Output (Random)
Final Counter: 982
Final Counter: 997
Final Counter: 1000 (sometimes)
👉 কারণ multiple goroutines একই সময় counter++ করছে
🧠 কেন এটা ঘটে? (Behind the Scenes)
counter++ আসলে এক ধাপে হয় না:
Read counter
Add 1
Write back
যদি দুই goroutine একসাথে পড়ে:
counter = 5
goroutine A reads 5
goroutine B reads 5
A writes 6
B writes 6 ❌ (one increment lost)
🧨 Why Race Condition is Dangerous?
| Risk | Why |
|---|---|
| Wrong data | Financial / banking bugs |
| Security issues | Auth / payment errors |
| Hard to debug | Sometimes works, sometimes fails |
| Production crashes | Random failures |
🛠️ How We Fix Race Condition? (Preview)
✅ Mutex (Lock)
✅ Atomic operations
✅ Channels
✅ Avoid shared state
🧪 Mini Mental Test
Race condition হবে কি এখানে?
var x = 0
go func() { x++ }()
go func() { x++ }()
👉 Yes — কারণ shared variable + parallel write
🧠 Mutex কী? (Simple Definition)
Mutex (Mutual Exclusion) এমন একটি lock যা নিশ্চিত করে যে এক সময় শুধুমাত্র একটি goroutine shared data access করতে পারবে।
অর্থাৎ:
এক goroutine কাজ করবে
বাকিরা wait করবে
কাজ শেষ হলে পরেরটি ঢুকবে
👉 এতে Race Condition বন্ধ হয়
📚 Go Mutex — Official Style Documentation
Package Import
import "sync"
Mutex Declare করা
var mu sync.Mutex
Lock এবং Unlock Syntax
mu.Lock() // critical section start
mu.Unlock() // critical section end
❌ Race Condition Example (Unsafe Code)
var counter = 0
func increment() {
counter++ // unsafe
}
✅ Mutex Fix (Safe Code)
package main
import (
"fmt"
"sync"
)
var counter = 0
var mu sync.Mutex
func increment(wg *sync.WaitGroup) {
defer wg.Done()
mu.Lock() // 🔒 Lock start
counter++ // safe update
mu.Unlock() // 🔓 Unlock end
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go increment(&wg)
}
wg.Wait()
fmt.Println("Final Counter:", counter)
}
🔐 How Mutex Prevents Race Condition?
Before (Race):
Multiple goroutines update at same time → ❌ wrong result
After (Mutex):
Only one goroutine updates at a time → ✅ correct result
🧠 Mental Model (Easy)
Think Mutex like a Bathroom Key 🚻
One person uses bathroom
Others wait outside
When finished → next enters
⚠️ Common Mistakes with Mutex
❌ Forgetting Unlock (Deadlock)
mu.Lock()
// no Unlock ❌ program stuck forever
✅ Safe Pattern (Use defer)
mu.Lock()
defer mu.Unlock()
❌ Lock too much code (Slow performance)
Lock only the critical section, not whole function.
⚙️ RWMutex (Read/Write Mutex)
Use when:
Many reads
Few writes
var mu sync.RWMutex
mu.RLock() // read lock
mu.RUnlock()
mu.Lock() // write lock
mu.Unlock()
🧪 Mini Practice Task
Fix this race condition using Mutex:
var balance = 1000
func withdraw(amount int) {
balance -= amount
}