Sobes.tech
Middle

Co je to mutex, jaké typy mutexů existují a jak je používat?

sobes.tech AI

Odpověď od AI

Mutex (z anglického MUTual EXclusion) je primitives synchronizace používaný k zajištění výlučného přístupu ke sdílenému zdroji mezi konkurenčními gorutinami. Zaručuje, že v jakémkoli okamžiku může vlastnit mutex pouze jedna gorutina a přistupovat k chráněným datům.

V Go balíček sync poskytuje dva hlavní typy mutexů:

  • sync.Mutex: Standardní mutex. Poskytuje metody Lock() a Unlock(). Pokud je mutex již zablokován, volání Lock() blokuje aktuální gorutinu, dokud nebude odblokována. Unlock() odblokuje mutex.

    var mu sync.Mutex
    var counter int
    
    func increment() {
        mu.Lock() // Zablokuje přístup k counter
        counter++
        mu.Unlock() // Odblokuje přístup
    }
    
  • sync.RWMutex: Mutex pro čtení/zápis. Umožňuje více gorutinám současně číst chráněný zdroj, ale pouze jedné zapisovat. Poskytuje metody Lock(), Unlock() (pro zápis), RLock() a RUnlock() (pro čtení).

    var rwMu sync.RWMutex
    var data []int
    
    func readData() {
        rwMu.RLock() // Zablokuje pro čtení
        // Čtení dat
        fmt.Println(data)
        rwMu.RUnlock() // Odblokuje čtení
    }
    
    func writeData(val int) {
        rwMu.Lock() // Zablokuje pro zápis
        // Zápis do dat
        data = append(data, val)
        rwMu.Unlock() // Odblokuje zápis
    }
    

Použití mutexů je nutné k prevenci race conditions, když více gorutin současně mění stejná data, což vede k nepředvídatelným výsledkům.

Pravidla použití:

  1. Zavolejte Lock() před přístupem ke chráněnému zdroji.
  2. Zavolejte Unlock() po dokončení přístupu. Doporučuje se používat defer mu.Unlock() pro zajištění odblokování i v případě paniky.
  3. Nesnažte se blokovat již zablokovaný mutex z téže gorutiny (může vést k deadlocku).
  4. Nesnažte se odblokovat nezablokovaný mutex.
  5. Při použití RWMutex používejte RLock/RUnlock pro čtení a Lock/Unlock pro zápis.
  6. Mutexy by neměly být kopírovány po prvním použití. Předávejte je odkazem nebo ukazatelem.

Příklad použití defer:

func safeIncrement() {
    mu.Lock()
    defer mu.Unlock() // Zajišťuje odblokování
    counter++
}