Skip to Content
Go Realm v1 is released 🎉
Go Routines🧭 Day 3

🧠 Go Concurrency Day 3 — WaitGroups & Mutex (Synchronization)

đŸŽ¯ āϞāĻ•ā§āĻˇā§āϝ

āφāϜ āϤ⧁āĻŽāĻŋ āĻļāĻŋāĻ–āĻŦ⧇ āϕ⧀āĻ­āĻžāĻŦ⧇ āĻāĻ•āĻžāϧāĻŋāĻ• goroutine āĻāĻ•āϏāĻžāĻĨ⧇ āϚāϞāϞ⧇āĻ“ āĻĒā§āϰ⧋āĻ—ā§āϰāĻžāĻŽ safe āĻāĻŦāĻ‚ predictable āϰāĻžāĻ–āĻž āϝāĻžā§ŸāĨ¤ āĻŽā§‚āϞāϤ āφāĻŽāϰāĻž āĻļāĻŋāĻ–āĻŦā§‹:

  • WaitGroup
  • Mutex / RWMutex
  • Race Condition
  • Race Detector (go run -race)
  • Channels āĻŦāύāĻžāĻŽ Mutex āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āĻŦ⧇ āωāĻĒāϝ⧁āĻ•ā§āϤ

āϕ⧇āύ synchronization āĻĻāϰāĻ•āĻžāϰ?

Go-āϤ⧇ goroutine āϗ⧁āϞ⧋ āĻāĻ•āχ āϏāĻžāĻĨ⧇ āϚāϞāϤ⧇ āĻĒāĻžāϰ⧇āĨ¤

āĻ•āĻŋāĻ¨ā§āϤ⧁ āϝāĻĻāĻŋ āϤāĻžāϰāĻž shared data āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇, āϤāĻ–āύ āϭ⧁āϞ āĻŽāĻžāύ, āĻ…āϏāĻžāĻŽāĻžā§āϜāĻ¸ā§āϝāĻĒā§‚āĻ°ā§āĻŖ āĻ…āĻŦāĻ¸ā§āĻĨāĻž, āĻ…āĻĨāĻŦāĻž race condition āϘāϟāϤ⧇ āĻĒāĻžāϰ⧇āĨ¤

1) WaitGroup āϕ⧀?

sync.WaitGroup āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāĻž āĻšā§Ÿ āĻāĻ•āĻžāϧāĻŋāĻ• goroutine āĻļ⧇āώ āĻšāĻ“ā§ŸāĻž āĻĒāĻ°ā§āϝāĻ¨ā§āϤ main function āϕ⧇ āĻ…āĻĒ⧇āĻ•ā§āώāĻž āĻ•āϰāĻžāύ⧋āϰ āϜāĻ¨ā§āϝāĨ¤

WaitGroup āĻĻāĻŋāϝāĻŧ⧇ āφāĻŽāϰāĻž āĻŦāϞāϤ⧇ āĻĒāĻžāϰāĻŋ:

“āĻāχ X āϏāĻ‚āĻ–ā§āϝāĻ• goroutine āĻļ⧇āώ āύāĻž āĻšāĻ“āϝāĻŧāĻž āĻĒāĻ°ā§āϝāĻ¨ā§āϤ main() āĻŦāĻ¨ā§āϧ āĻšāĻŦ⧇ āύāĻžāĨ¤â€

🔹 āĻŽā§‚āϞ āϤāĻŋāύāϟāĻŋ āĻŽā§‡āĻĨāĻĄ

āĻŽā§‡āĻĨāĻĄāĻ•āĻžāϜ
Add(n)n āϟāĻŋ goroutine āĻļ⧁āϰ⧁ āĻšāĻŦ⧇ āϤāĻž WaitGroup-āϕ⧇ āϜāĻžāύāĻžāύ⧋
Done()āĻāĻ•āϟāĻŋ goroutine āĻ•āĻžāϜ āĻļ⧇āώ āϤāĻž WaitGroup-āϕ⧇ āϜāĻžāύāĻžāύ⧋
Wait()āϏāĻŦ Done() āύāĻž āĻšāĻ“āϝāĻŧāĻž āĻĒāĻ°ā§āϝāĻ¨ā§āϤ main() āĻ…āĻĒ⧇āĻ•ā§āώāĻž āĻ•āϰ⧇

🔸 āωāĻĻāĻžāĻšāϰāĻŖ: ā§ĢāϟāĻŋ goroutine āϚāĻžāϞāĻŋāϝāĻŧ⧇ WaitGroup āĻĻāĻŋāϝāĻŧ⧇ āĻ…āĻĒ⧇āĻ•ā§āώāĻž

package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup wg.Add(5) // ā§ĢāϟāĻž goroutine āĻšāĻŦ⧇ for i := 1; i <= 5; i++ { go func(id int) { defer wg.Done() fmt.Println("Goroutine āϚāϞāϛ⧇:", id) }(i) } wg.Wait() // āϏāĻŦ goroutine āĻļ⧇āώ āύāĻž āĻšāĻ“āϝāĻŧāĻž āĻĒāĻ°ā§āϝāĻ¨ā§āϤ āĻ…āĻĒ⧇āĻ•ā§āώāĻž fmt.Println("āϏāĻŦ goroutine āĻļ⧇āώ āĻšāϝāĻŧ⧇āϛ⧇ ✅") }

🧩 āϕ⧀ āĻšāϞ⧋ āĻāĻ–āĻžāύ⧇: WaitGroup main function āϕ⧇ āĻŦā§āϞāĻ• āĻ•āϰ⧇ āϰāĻžāĻ–āϛ⧇ āϝāϤāĻ•ā§āώāĻŖ āύāĻž āϏāĻŦ goroutine āĻļ⧇āώ āĻšā§ŸāĨ¤


2) Shared Data + Mutex

Mutex-āĻāϰ āĻĒā§‚āĻ°ā§āĻŖāϰ⧂āĻĒ āĻšāϞ⧋ “Mutual Exclusion” (āĻĒāĻžāϰāĻ¸ā§āĻĒāϰāĻŋāĻ• āĻŦāĻ°ā§āϜāύ)āĨ¤

āĻāϰ āĻŽā§‚āϞ āϧāĻžāϰāĻŖāĻž āĻšāϞ⧋: āĻāĻ•āχ āϏāĻŽāϝāĻŧ⧇ āĻļ⧁āϧ⧁āĻŽāĻžāĻ¤ā§āϰ āĻāĻ•āϟāĻŋ goroutine-āϕ⧇ āĻāĻ•āϟāĻŋ āύāĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āϟ āĻĄā§‡āϟāĻž (shared data) āĻ…ā§āϝāĻžāĻ•ā§āϏ⧇āϏ āĻŦāĻž āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰāĻžāϰ āĻ…āύ⧁āĻŽāϤāĻŋ āĻĻ⧇āĻ“āϝāĻŧāĻžāĨ¤


âš ī¸ āϏāĻŽāĻ¸ā§āϝāĻž: Data Race

āϝāĻ–āύ āĻāĻ•āĻžāϧāĻŋāĻ• goroutine đŸ”ĨāĻāĻ•āχ datađŸ”Ĩ āĻāĻ•āϝ⧋āϗ⧇ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰāĻžāϰ āĻšā§‡āĻˇā§āϟāĻž āĻ•āϰ⧇, āϤāĻ–āύ data race āύāĻžāĻŽāĻ• āĻāĻ•āϟāĻŋ āĻŽāĻžāϰāĻžāĻ¤ā§āĻŽāĻ• āĻŦāĻžāĻ— āϤ⧈āϰāĻŋ āĻšā§ŸāĨ¤ āĻāϰ āĻĢāϞ⧇ āĻĄā§‡āϟāĻž āύāĻˇā§āϟ (corrupt) āĻšā§Ÿā§‡ āϝ⧇āϤ⧇ āĻĒāĻžāϰ⧇ āĻŦāĻž āĻ…ā§āϝāĻžāĻĒā§āϞāĻŋāϕ⧇āĻļāύāϟāĻŋ āĻ•ā§āĻ°ā§āϝāĻžāĻļ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āĨ¤

🔒 āϏāĻŽāĻžāϧāĻžāύ: sync.Mutex

Go-āϤ⧇ āĻāχ data race āϠ⧇āĻ•āĻžāύ⧋āϰ āϜāĻ¨ā§āϝ sync āĻĒā§āϝāĻžāϕ⧇āĻœā§‡āϰ Mutex āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāĻž āĻšāϝāĻŧāĨ¤ āĻāϟāĻŋ āĻāĻ•āϟāĻŋ āϤāĻžāϞāĻžāϰ (lock) āĻŽāϤ⧋ āĻ•āĻžāϜ āĻ•āϰ⧇āĨ¤

āĻāϰ āĻĻ⧁āϟāĻŋ āĻĒā§āϰāϧāĻžāύ āĻŽā§‡āĻĨāĻĄ āϰāϝāĻŧ⧇āϛ⧇:

  • Lock(): āĻĄā§‡āϟāĻž āĻ…ā§āϝāĻžāĻ•ā§āϏ⧇āϏ āĻ•āϰāĻžāϰ āφāϗ⧇ āĻāχ āĻŽā§‡āĻĨāĻĄ āĻ•āϞ āĻ•āϰāĻž āĻšā§ŸāĨ¤

    • āϝāĻĻāĻŋ āϤāĻžāϞāĻžāϟāĻŋ āĻ–ā§‹āϞāĻž āĻĨāĻžāϕ⧇, āϤāĻŦ⧇ goroutine-āϟāĻŋ āĻāϟāĻŋ āϞāĻ• āĻ•āϰ⧇ āĻāĻŦāĻ‚ āĻ•āĻžāϜ āĻļ⧁āϰ⧁ āĻ•āϰ⧇āĨ¤
    • āϝāĻĻāĻŋ āĻ…āĻ¨ā§āϝ goroutine āφāϗ⧇āχ āϞāĻ• āĻ•āϰ⧇ āϰāĻžāϖ⧇, āϤāĻŦ⧇ āĻāϟāĻŋ āϤāĻžāϞāĻž āĻ–ā§‹āϞāĻžāϰ āϜāĻ¨ā§āϝ āĻ…āĻĒ⧇āĻ•ā§āώāĻž (block) āĻ•āϰ⧇āĨ¤
  • Unlock(): āĻĄā§‡āϟāĻž āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰāĻž āĻļ⧇āώ āĻšāϞ⧇ āĻāχ āĻŽā§‡āĻĨāĻĄ āĻ•āϞ āĻ•āϰāĻž āĻšā§ŸāĨ¤

    • āĻāϟāĻŋ āϤāĻžāϞāĻžāϟāĻŋ āϖ⧁āϞ⧇ āĻĻ⧇āϝāĻŧ, āϝāĻžāϤ⧇ āĻ…āĻĒ⧇āĻ•ā§āώāĻžāϰāϤ āĻ…āĻ¨ā§āϝ goroutine-āϗ⧁āϞāĻŋ āĻĄā§‡āϟāĻž āĻ…ā§āϝāĻžāĻ•ā§āϏ⧇āϏ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āĨ¤

🔸 āωāĻĻāĻžāĻšāϰāĻŖ: 1000 āĻŦāĻžāϰ Counter āĻŦ⧃āĻĻā§āϧāĻŋ (Safe)

package main import ( "fmt" "sync" ) func main() { var counter = 0 var mu sync.Mutex var wg sync.WaitGroup wg.Add(1000) for i := 0; i < 1000; i++ { go func() { defer wg.Done() mu.Lock() counter++ // āĻāĻ–āύ āύāĻŋāϰāĻžāĻĒāĻĻ mu.Unlock() }() } wg.Wait() fmt.Println("Final Counter:", counter) }

🔒 āĻāĻ–āĻžāύ⧇ Mutex counter-āϕ⧇ āĻāĻ•āϏāĻžāĻĨ⧇ āĻāĻ• goroutine āĻĻā§āĻŦāĻžāϰāĻž āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āύāĻŋāĻļā§āϚāĻŋāϤ āĻ•āϰāϛ⧇āĨ¤


3) Mutex āĻŦāĻžāĻĻ āĻĻāĻŋāϞ⧇ āϕ⧀ āĻšāϝāĻŧ? (Race Condition!)

package main import ( "fmt" "sync" ) func main() { var counter = 0 var wg sync.WaitGroup wg.Add(1000) for i := 0; i < 1000; i++ { go func() { defer wg.Done() counter++ // ❌ āĻŦāĻŋāĻĒāĻĻ! āĻāĻ•āĻžāϧāĻŋāĻ• goroutine āĻāĻ•āϏāĻžāĻĨ⧇ āϞāĻŋāĻ–āϛ⧇ }() } wg.Wait() fmt.Println("Final Counter:", counter) }

đŸ’Ĩ Output āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύāĻļā§€āϞ āĻšāĻŦ⧇ — āĻ•āĻ–āύāĻ“ 800, āĻ•āĻ–āύāĻ“ 950, āĻ•āĻ–āύāĻ“ 1000 āύāĻžāĨ¤ āĻāϟāĻžāχ Race ConditionāĨ¤


4) Race Detector āĻŦā§āϝāĻŦāĻšāĻžāϰ

Go-āϤ⧇ āĻŦāĻŋāĻ˛ā§āϟ-āχāύ race detector āφāϛ⧇āĨ¤

go run -race main.go

āĻāϟāĻŋ āĻŦāϞāĻŦ⧇:

WARNING: DATA RACE Read at ... Previous write at ...

āĻāϰ āĻŽāĻžāύ⧇ āϤ⧋āĻŽāĻžāϰ āϕ⧋āĻĄā§‡ āĻāĻ•āĻžāϧāĻŋāĻ• goroutine āĻāĻ•āϏāĻžāĻĨ⧇ data āĻ…ā§āϝāĻžāĻ•ā§āϏ⧇āϏ āĻ•āϰāϛ⧇āĨ¤


📌 5) RWMutex (Reader-Writer Mutex)

🔐 RWMutex (Reader–Writer Mutex)

sync.RWMutex āĻšāϞ⧋ āĻāĻŽāύ āĻāĻ•āϟāĻŋ āϞāĻ• āϝāĻž readâŦ†ī¸ āĻŦ⧇āĻļāĻŋ āĻ“ writeâŦ‡ī¸ āĻ•āĻŽ āĻ•āĻžāĻœā§‡āϰ āĻ•ā§āώ⧇āĻ¤ā§āϰ⧇ āĻĒāĻžāϰāĻĢāϰāĻŽā§āϝāĻžāĻ¨ā§āϏ āĻŦāĻžā§œāĻžā§ŸāĨ¤


âš™ī¸ āĻ•āĻžāĻœā§‡āϰ āύāĻŋ⧟āĻŽ

RWMutex āĻĻ⧁āϟāĻŋ āφāϞāĻžāĻĻāĻž āϞāĻ• āĻĻā§‡ā§Ÿ:

  • RLock() → āĻāĻ•āĻžāϧāĻŋāĻ• goroutine āĻāĻ•āϏāĻžāĻĨ⧇ data read āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇
  • Lock() → āĻļ⧁āϧ⧁āĻŽāĻžāĻ¤ā§āϰ āĻāĻ•āϟāĻŋ goroutine data write āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇ (āϏāĻŦ readers āĻ“ writers āĻŦā§āϞāĻ• āĻšā§Ÿ)

📖 āωāĻĻāĻžāĻšāϰāĻŖ

var ( value int mu sync.RWMutex ) func reader(id int, wg *sync.WaitGroup) { defer wg.Done() mu.RLock() fmt.Println("Reader", id, "read:", value) mu.RUnlock() } func writer(wg *sync.WaitGroup) { defer wg.Done() mu.Lock() value++ fmt.Println("Writer updated value:", value) mu.Unlock() }

🔹 āĻāĻ–āĻžāύ⧇:

  • āĻāĻ•āĻžāϧāĻŋāĻ• reader() āĻāĻ•āχ āϏāĻŽā§Ÿā§‡ āϚāĻžāϞāϤ⧇ āĻĒāĻžāϰ⧇
  • āĻ•āĻŋāĻ¨ā§āϤ⧁ writer() āφāϏāϞ⧇, āĻ…āĻ¨ā§āϝ āϏāĻŦāĻžāχ đŸ”Ĩ āĻĨ⧇āĻŽā§‡ āϝāĻžā§Ÿ āϝāϤāĻ•ā§āώāĻŖ āύāĻž writer āĻ•āĻžāϜ āĻļ⧇āώ āĻ•āϰ⧇

⚡ āϕ⧇āύ RWMutex āĻĻāϰāĻ•āĻžāϰ?

āϧāϰ⧋ āϤ⧋āĻŽāĻžāϰ āĻĒā§āϰ⧋āĻ—ā§āϰāĻžāĻŽ ⧝ā§Ļ% āϏāĻŽā§Ÿ āĻļ⧁āϧ⧁ read āĻ•āϰ⧇, āφāϰ ā§§ā§Ļ% āϏāĻŽā§Ÿ write āĻ•āϰ⧇āĨ¤ āϝāĻĻāĻŋ āϏāĻžāϧāĻžāϰāĻŖ Mutex āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧋, āϤāĻžāĻšāϞ⧇ āϏāĻŦ reader āĻāϕ⧇ āĻāϕ⧇ āϚāϞāĻŦ⧇ — āĻĒāĻžāϰāĻĢāϰāĻŽā§āϝāĻžāĻ¨ā§āϏ āĻ•āĻŽā§‡ āϝāĻžāĻŦ⧇āĨ¤

RWMutex āĻāχ āϏāĻŽāĻ¸ā§āϝāĻž āϏāĻŽāĻžāϧāĻžāύ āĻ•āϰ⧇:

  • āĻāĻ•āĻžāϧāĻŋāĻ• reader āĻāĻ•āϏāĻžāĻĨ⧇ read āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇ (concurrent read)
  • āĻ•āĻŋāĻ¨ā§āϤ⧁ writer āφāϏāϞ⧇ āϏāĻŦāĻžāχ āĻŦā§āϞāĻ• āĻšāĻŦ⧇ āϝāϤāĻ•ā§āώāĻŖ āύāĻž writer āĻ•āĻžāϜ āĻļ⧇āώ āĻ•āϰ⧇

âš–ī¸ Mutex āĻŦāύāĻžāĻŽ RWMutex

āĻĻāĻŋāĻ•MutexRWMutex
āĻāĻ•āĻžāϧāĻŋāĻ• reader āĻāĻ•āϏāĻžāĻĨā§‡âŒ āύāĻžâœ… āĻšā§āϝāĻžāρ
āĻāĻ•āĻžāϧāĻŋāĻ• writer āĻāĻ•āϏāĻžāĻĨā§‡âŒ āύāĻžâŒ āύāĻž
Read-heavy workload āĻ performanceāϧ⧀āϰāĻĻā§āϰ⧁āϤ
āĻŦā§āϝāĻŦāĻšāĻžāϰShared data āĻ•āĻŽ āĻĒ⧜āĻž āĻšā§ŸShared data āĻŦ⧇āĻļāĻŋ āĻĒ⧜āĻž āĻšā§Ÿ

✅ āĻŽāύ⧇ āϰāĻžāĻ–ā§‹

RWMutex āϤāĻ–āύ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧋, āϝāĻ–āύ read āĻ…āύ⧇āĻ• āĻŦ⧇āĻļāĻŋ āφāϰ write āĻ•āĻŽāĨ¤ Write āĻāϞ⧇ āϏāĻŦāĻžāχ āĻ…āĻĒ⧇āĻ•ā§āώāĻž āĻ•āϰāĻŦ⧇; Read āĻāϞ⧇ āϏāĻŦāĻžāχ āĻāĻ•āϏāĻžāĻĨ⧇ āĻ•āĻžāϜ āĻ•āϰāĻŦ⧇āĨ¤

🔍 Channels āĻŦāύāĻžāĻŽ Mutex

āĻĒāϰāĻŋāĻ¸ā§āĻĨāĻŋāϤāĻŋāĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰāĻŖ
Shared variable āϰāĻ•ā§āώāĻž āĻ•āϰāϤ⧇ āĻšāĻŦ⧇MutexāϏāĻšāϜ āĻ“ āĻ•āĻžāĻ°ā§āϝāĻ•āϰ
Data goroutine-āĻāϰ āĻŽāĻ§ā§āϝ⧇ āφāĻĻāĻžāύ-āĻĒā§āϰāĻĻāĻžāύ āĻ•āϰāϤ⧇ āĻšāĻŦ⧇ChannelOwnership āĻ¸ā§āĻĒāĻˇā§āϟ āĻ“ race-free
Pipeline āĻŦāĻž Worker-Pool āĻĄāĻŋāϜāĻžāχāύChannelNatural fit

🧩 āĻ…āύ⧁āĻļā§€āϞāύ

ExerciseāĻ•āĻžāϜ
1ī¸âƒŖā§ĢāϟāĻŋ goroutine āϚāĻžāϞāĻžāĻ“ āĻ“ WaitGroup āĻĻāĻŋā§Ÿā§‡ āĻļ⧇āώ āĻĒāĻ°ā§āϝāĻ¨ā§āϤ āĻ…āĻĒ⧇āĻ•ā§āώāĻž āĻ•āϰāĻžāĻ“
2ī¸âƒŖCounter 1000 āĻŦāĻžāϰ āĻŦ⧃āĻĻā§āϧāĻŋ āĻ•āϰ⧋ Mutex āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇
3ī¸âƒŖMutex āϏāϰāĻžāĻ“ āĻ“ āĻĻ⧇āĻ–ā§‹ āϕ⧀ āĻšā§Ÿ
4ī¸âƒŖgo run -race main.go āĻĻāĻŋā§Ÿā§‡ race detector āϚāĻžāϞāĻžāĻ“
5ī¸âƒŖRWMutex āĻĻāĻŋā§Ÿā§‡ āĻāĻ• Writer āĻ“ āĻāĻ•āĻžāϧāĻŋāĻ• Reader āϚāĻžāϞāĻžāĻ“

🧭 āϏāĻžāϰāϏāĻ‚āĻ•ā§āώ⧇āĻĒ

āϧāĻžāϰāĻŖāĻžāĻ•āĻžāϜ
WaitGroupāĻāĻ•āĻžāϧāĻŋāĻ• goroutine āĻļ⧇āώ āĻšāĻ“ā§ŸāĻž āĻĒāĻ°ā§āϝāĻ¨ā§āϤ āĻ…āĻĒ⧇āĻ•ā§āώāĻž
MutexShared variable āϕ⧇ āĻāĻ•āϏāĻŽā§Ÿ āĻāĻ• goroutine āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰāϤ⧇ āĻĻā§‡ā§Ÿ
RWMutexāĻāĻ•āĻžāϧāĻŋāĻ• reader āĻāĻ•āχ āϏāĻžāĻĨ⧇, āĻ•āĻŋāĻ¨ā§āϤ⧁ writer āĻāĻ•āĻž
Race ConditionāĻāĻ•āĻžāϧāĻŋāĻ• goroutine āĻāĻ•āϏāĻžāĻĨ⧇ shared data āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰāϞ⧇ āĻšā§Ÿ
-race flagRace Condition āĻļāύāĻžāĻ•ā§āϤ āĻ•āϰāĻžāϰ āϟ⧁āϞ
Channel āĻŦāύāĻžāĻŽ MutexChannel data pass āĻ•āϰāϤ⧇, đŸ”ĨMutex data protect āĻ•āϰāϤ⧇ đŸ”Ĩ