Menu
Coddy logo textTech

sync.Mutex ve sync.RWMutex

Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 63 / 107.

Kanallar, Go’nun goroutine’leri koordine etmek için tercih ettiği yol olsa da bazen paylaşılan verileri doğrudan korumanız gerekir. sync paketi mutex’ler sağlar: bir kaynağa aynı anda yalnızca bir goroutine’in erişmesini sağlayan kilitler.

Bir sync.Mutex iki yönteme sahiptir: Lock() ve Unlock(). Bir goroutine Lock() çağırdığında özel erişim elde eder. Lock() çağıran diğer goroutine'ler, Unlock() çağrılana kadar engellenir:

type Counter struct {
    mu    sync.Mutex
    value int
}

func (c *Counter) Increment() {
    c.mu.Lock()
    c.value++
    c.mu.Unlock()
}

func (c *Counter) Value() int {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.value
}

defer c.mu.Unlock() kullanmak, işlev erken dönerse veya panik yaparsa bile kilidin serbest bırakılmasını sağlar: yaygın ve önerilen bir kalıp.

Okuma işlemleri sık ancak yazma işlemleri nadir olduğunda sync.RWMutex daha iyi performans sunar. Birden fazla okuyucunun eşzamanlı olarak çalışmasına izin verir, ancak yazıcılar özel erişim elde eder:

type Cache struct {
    mu   sync.RWMutex
    data map[string]string
}

func (c *Cache) Get(key string) string {
    c.mu.RLock()         // birden fazla okuyucuya izin verilir
    defer c.mu.RUnlock()
    return c.data[key]
}

func (c *Cache) Set(key, value string) {
    c.mu.Lock()          // yazma için özel erişim
    defer c.mu.Unlock()
    c.data[key] = value
}

Okuma işlemleri için RLock()/RUnlock(), yazma işlemleri için Lock()/Unlock() kullanın. Bu, yazma işlemlerinin güvenli olmasını sağlarken eşzamanlı okumalara olanak tanır.

challenge icon

Görev

Kolay

Ürün stok düzeylerini izleyen iş parçacığı güvenli bir envanter sistemi oluşturalım. Sisteminiz, birden fazla işlem aynı anda gerçekleştiğinde veri bütünlüğünü sağlayarak mutex'leri kullanıp eşzamanlı okuma ve yazma işlemlerini güvenli şekilde yönetecek.

Kodunuzu iki dosyaya ayıracaksınız:

  • inventory.go: İş parçacığı güvenli envanter yönetim sisteminizi tanımlayın.

    Ürün miktarlarını bir map içinde depolayan ve erişimi korumak için Inventory kullanan bir sync.RWMutex struct'ı oluşturun. Envanteriniz şu işlemleri desteklemelidir:

    • NewInventory() *Inventory - Başlatılmış bir map içeren yeni bir envanter oluşturur
    • AddStock(product string, quantity int) - Bir ürünün stoğuna miktar ekler (verileri değiştirdiği için özel kilit kullanın)
    • GetStock(product string) int - Bir ürünün mevcut stok miktarını veya ürün bulunamazsa 0 döndürür (yalnızca veri okuduğu için okuma kilidi kullanın)
    • RemoveStock(product string, quantity int) bool - Yeterli stok varsa stoktan miktar çıkarır. İşlem başarılıysa true, stok yetersizse false döndürür (özel kilit kullanın)

    Kilitlerin her zaman düzgün şekilde serbest bırakılmasını sağlamak için kilitleri kaldırırken defer kullanmayı unutmayın.

  • main.go: İşlemleri okuyun ve iş parçacığı güvenli envanterinizi gösterin.

    İşlem sayısını okuyun, ardından her işlemi işleyin. Her işlemin bir türü (add, get veya remove), bir ürün adı ve add/remove işlemleri için bir miktarı vardır.

    Her işlem için sonucu yazdırın:

    • add: Added [quantity] [product] yazdırın
    • get: [product]: [stock] in stock yazdırın
    • remove: Başarılıysa Removed [quantity] [product], değilse Insufficient stock for [product] yazdırın

Aşağıdaki girdiler sağlanacaktır:

  • 1. satır: İşlem sayısı (tam sayı)
  • Sonraki satırlar: Her işlem için:
    • İşlem türü (add, get veya remove)
    • Ürün adı
    • Miktar (yalnızca add ve remove işlemleri için)

Örneğin, şu verildiğinde:

5
add
apples
50
get
apples
remove
apples
30
remove
apples
25
get
apples

Çıktınız şu şekilde olmalıdır:

Added 50 apples
apples: 50 in stock
Removed 30 apples
Insufficient stock for apples
apples: 20 in stock

RWMutex, birden fazla GetStock çağrısının aynı anda okuma yapmasına izin verirken AddStock ve RemoveStock, envanteri değiştirirken özel erişim elde eder.

Kendin dene

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// İşlem sayısını oku
	line, _ := reader.ReadString('\n')
	numOps, _ := strconv.Atoi(strings.TrimSpace(line))
	
	// Yeni bir envanter oluştur
	inventory := NewInventory()
	
	// Her işlemi işle
	for i := 0; i < numOps; i++ {
		// İşlem türünü oku
		opLine, _ := reader.ReadString('\n')
		opType := strings.TrimSpace(opLine)
		
		// Ürün adını oku
		productLine, _ := reader.ReadString('\n')
		product := strings.TrimSpace(productLine)
		
		// TODO: Her işlem türünü işle (add, get, remove)
		// "add" ve "remove" için, miktarı girdiden oku
		// Uygun envanter metodunu çağır
		// Sonucu challenge açıklamasına göre yazdır
		
		switch opType {
		case "add":
			// TODO: Miktarı oku, stok ekle, sonucu yazdır
			
		case "get":
			// TODO: Stoku al, sonucu yazdır
			
		case "remove":
			// TODO: Miktarı oku, stok çıkar, uygun sonucu yazdır
			
		}
	}
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler

Kendi başına pratik yap: Online Go derleyicisi