Skip to Content

Mutex

Bir nechta goroutine bitta o’zgaruvchini bir vaqtda o’zgartirsa, race condition kelib chiqadi: natija goroutine’lar qay tartibda ishlaganiga bog’lanib qoladi. counter++ aslida uch qadam (o’qi, oshir, yoz), shuning uchun ikki goroutine baravar oshirsa, bir oshirish “yo’qolib” ketishi mumkin.

sync.Mutex — qulf. Lock() bilan qulflaysiz, Unlock() bilan ochasiz; bir vaqtda qulfni faqat bitta goroutine ushlab turadi, qolganlar navbat kutadi:

mutex.go
package main import ( "fmt" "sync" ) func main() { counter := 0 var mu sync.Mutex var wg sync.WaitGroup for range 1000 { wg.Add(1) go func() { defer wg.Done() mu.Lock() counter++ // qulf ichida - xavfsiz mu.Unlock() }() } wg.Wait() fmt.Println("counter:", counter) }
$ go run mutex.go counter: 1000

Qulfsiz bo’lsa, bu kod ko’pincha 1000 dan kam (masalan 973) chiqaradi. Lock/Unlock esa counter++ ni bo’linmas qilib qo’ydi.

Race detector va RWMutex

Bunday xatolarni Go’ning -race bayrog’i tutib oladi — go run -race mutex.go qaysi qatorda, qaysi goroutine’lar to’qnashayotganini aniq ko’rsatadi (WARNING: DATA RACE). Concurrent kodni har doim -race bilan sinang.

Ma’lumot ko’p o’qilib, kam yozilsa (kesh, konfiguratsiya), sync.RWMutex tezroq: RLock()/RUnlock() bir vaqtda ko’p o’quvchiga ruxsat beradi, Lock()/Unlock() esa faqat bitta yozuvchiga. Mutex’ni u himoyalayotgan ma’lumot bilan bitta struct’ga joylash — yaxshi uslub:

rwmutex.go
package main import ( "fmt" "sync" ) type Config struct { mu sync.RWMutex data map[string]string } func (c *Config) Get(key string) string { c.mu.RLock() defer c.mu.RUnlock() return c.data[key] } func (c *Config) Set(key, val string) { c.mu.Lock() defer c.mu.Unlock() c.data[key] = val } func main() { cfg := &Config{data: make(map[string]string)} cfg.Set("host", "localhost") var wg sync.WaitGroup for range 3 { wg.Add(1) go func() { defer wg.Done() fmt.Println("host:", cfg.Get("host")) // bir vaqtda o'qish xavfsiz }() } wg.Wait() }
$ go run rwmutex.go host: localhost host: localhost host: localhost

Map’lar o’z-o’zidan goroutine uchun xavfsiz emas (fatal error: concurrent map writes) — mutex ularni ham himoya qiladi.

Qisqasi: Mutex umumiy holatni race’dan himoyalaydi; o’qish ko’p bo’lsa RWMutex ishlating; xatolarni esa go run -race topib beradi.

Manba / batafsil: pkg.go.dev/sync#Mutex , Data Race Detector 

Oddiy hisoblagichlar uchun mutex biroz og’irlik qiladi — avval sync.Once, so’ng undan tezroq sync/atomic ni ko’ramiz.

Last updated on