GoDasturchi
Mutex-Protected Containers

Mutex-Protected Containers

Mutex bilan himoyalangan tuzilmalar

Oldingi darsda ko'rgan muammoning eng sodda yechimi — bir vaqtning o'zida faqat bitta goroutine'ga tuzilmaga tegishga ruxsat berish. Bu — bitta hojatxona kaliti kabi: kalit sizda bo'lsa, ichkariga faqat siz kirasiz; boshqalar tashqarida navbat kutadi.

Go'da bu "kalit" — sync.Mutex ("mutual exclusion", "o'zaro istisno"). Uni Stack'imizga qo'shib, har bir amal atrofida "kalitni oling — ishni bajaring — kalitni qaytaring" tartibini o'rnatamiz.

example.go
package main

import (
	"fmt"
	"sync"
)

type SafeStack struct {
	mu    sync.Mutex
	items []int
}

func (s *SafeStack) Push(v int) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.items = append(s.items, v)
}

func (s *SafeStack) Len() int {
	s.mu.Lock()
	defer s.mu.Unlock()
	return len(s.items)
}

func main() {
	var s SafeStack
	var wg sync.WaitGroup

	for i := 0; i < 100; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			s.Push(1)
		}()
	}
	wg.Wait()

	fmt.Println(s.Len())
}

s.mu.Lock() — "kalitni olish": agar boshqa goroutine allaqachon ushlab tursa, joriy goroutine shu yerda kutadi, toki kalit bo'shaguncha. defer s.mu.Unlock() — funksiya tugaganda kalitni albatta qaytarish ("Errors Are Values" va "defer" darslaridan tanish naqsh). Natijada, 100 ta goroutine bir vaqtda ishga tushirilsa ham, Push amalining o'zi hech qachon ikkitasi bir vaqtda bajarilmaydi — ular navbat bilan, bittalab kiradi.

Shuning uchun natija har doim aniq 100 bo'ladi — race condition yo'qolgan, chunki endi items = append(...) operatsiyasi hech qachon "yarim bajarilgan" holatda boshqa goroutine tomonidan ko'rilmaydi.

>_ Exercise

SafeQueue — Mutex bilan himoyalangan navbat yasang.

  • SafeQueue struct'i (sync.Mutex + items []int) yasang
  • Enqueue(v int) — Lock/Unlock bilan himoyalangan holda qo'shing
  • Len() int — Lock/Unlock bilan himoyalangan holda uzunlikni qaytaring
  • 50 ta goroutine bilan Enqueue qiling, WaitGroup bilan kuting, so'ng Len()ni chop eting

Stuck? Reveal a hint to help you.

Hints (0/3)

Key Takeaway

Key Takeaway:

sync.Mutex bilan har bir amalni "Lock — ish — Unlock" bilan o'rab, bir vaqtning o'zida faqat bitta goroutine tuzilmaga tegishini ta'minlash — race condition'ning eng sodda va keng tarqalgan yechimi.

NEXT UP

sync.Map Deep Dive

OUTPUT

$ go run main.go
Kodingizni ishga tushiring

Mutex-Protected Containers

Mutex bilan himoyalangan tuzilmalar

Oldingi darsda ko'rgan muammoning eng sodda yechimi — bir vaqtning o'zida faqat bitta goroutine'ga tuzilmaga tegishga ruxsat berish. Bu — bitta hojatxona kaliti kabi: kalit sizda bo'lsa, ichkariga faqat siz kirasiz; boshqalar tashqarida navbat kutadi.

Go'da bu "kalit" — sync.Mutex ("mutual exclusion", "o'zaro istisno"). Uni Stack'imizga qo'shib, har bir amal atrofida "kalitni oling — ishni bajaring — kalitni qaytaring" tartibini o'rnatamiz.

example.go
package main

import (
	"fmt"
	"sync"
)

type SafeStack struct {
	mu    sync.Mutex
	items []int
}

func (s *SafeStack) Push(v int) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.items = append(s.items, v)
}

func (s *SafeStack) Len() int {
	s.mu.Lock()
	defer s.mu.Unlock()
	return len(s.items)
}

func main() {
	var s SafeStack
	var wg sync.WaitGroup

	for i := 0; i < 100; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			s.Push(1)
		}()
	}
	wg.Wait()

	fmt.Println(s.Len())
}

s.mu.Lock() — "kalitni olish": agar boshqa goroutine allaqachon ushlab tursa, joriy goroutine shu yerda kutadi, toki kalit bo'shaguncha. defer s.mu.Unlock() — funksiya tugaganda kalitni albatta qaytarish ("Errors Are Values" va "defer" darslaridan tanish naqsh). Natijada, 100 ta goroutine bir vaqtda ishga tushirilsa ham, Push amalining o'zi hech qachon ikkitasi bir vaqtda bajarilmaydi — ular navbat bilan, bittalab kiradi.

Shuning uchun natija har doim aniq 100 bo'ladi — race condition yo'qolgan, chunki endi items = append(...) operatsiyasi hech qachon "yarim bajarilgan" holatda boshqa goroutine tomonidan ko'rilmaydi.

>_ Exercise

SafeQueue — Mutex bilan himoyalangan navbat yasang.

  • SafeQueue struct'i (sync.Mutex + items []int) yasang
  • Enqueue(v int) — Lock/Unlock bilan himoyalangan holda qo'shing
  • Len() int — Lock/Unlock bilan himoyalangan holda uzunlikni qaytaring
  • 50 ta goroutine bilan Enqueue qiling, WaitGroup bilan kuting, so'ng Len()ni chop eting

Stuck? Reveal a hint to help you.

Hints (0/3)

Key Takeaway

Key Takeaway:

sync.Mutex bilan har bir amalni "Lock — ish — Unlock" bilan o'rab, bir vaqtning o'zida faqat bitta goroutine tuzilmaga tegishini ta'minlash — race condition'ning eng sodda va keng tarqalgan yechimi.

NEXT UP

sync.Map Deep Dive