Header Ads

Header ADS

Race Condition & Mutex in Go Concurrency

 



🧠 Race Condition কী? (Simple Definition)

Race Condition ঘটে যখন একাধিক goroutine একই data একসাথে read/write করে, এবং final result unpredictable হয়ে যায়।

অর্থাৎ:

  1. কে আগে চলবে — তার ওপর output বদলে যায়

  2. Result হয় random এবং unreliable


🏃 Real-Life Example (Easy to Imagine)

ধরো:

  1. তোমার এবং তোমার বন্ধুর কাছে একই ব্যাংক অ্যাকাউন্ট

  2. দুজনেই একসাথে টাকা তুলছো

  3. ব্যালেন্স আপডেট হচ্ছে 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++ আসলে এক ধাপে হয় না:

  1. Read counter

  2. Add 1

  3. 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?

RiskWhy
Wrong dataFinancial / banking bugs
Security issuesAuth / payment errors
Hard to debugSometimes works, sometimes fails
Production crashesRandom 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 করতে পারবে

অর্থাৎ:

  1. এক goroutine কাজ করবে

  2. বাকিরা wait করবে

  3. কাজ শেষ হলে পরেরটি ঢুকবে

👉 এতে 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 🚻

  1. One person uses bathroom

  2. Others wait outside

  3. 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:

  1. Many reads

  2. 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
}



Powered by Blogger.