Sobes.tech
Middle

Čo je mutex, aké typy mutexov existujú a ako ich používať?

sobes.tech AI

Odpoveď od AI

Mutex (od ang. MUTual EXclusion) je primitiv za sinhronizaciju koji se koristi za obezbeđivanje isključivog pristupa deljenom resursu između konkurentnih gorutina. On garantuje da u bilo kojem trenutku samo jedna gorutina može posedovati mutex i, shodno tome, pristupati zaštićenim podacima.

U Go, paket sync pruža dve glavne vrste mutexa:

  • sync.Mutex: Standardni mutex. Pruža metode Lock() i Unlock(). Ako je mutex već zaključan, poziv Lock() blokira trenutnu gorutinu dok se ne oslobodi. Unlock() otključava mutex.

    var mu sync.Mutex
    var counter int
    
    func increment() {
        mu.Lock() // Zaključavamo pristup prema counter
        counter++
        mu.Unlock() // Otključavamo pristup
    }
    
  • sync.RWMutex: Mutex za čitanje/zapis. Omogućava više gorutina da istovremeno čitaju zaštićeni resurs, ali samo jednu da piše. Pruža metode Lock(), Unlock() (za zapis), RLock() i RUnlock() (za čitanje).

    var rwMu sync.RWMutex
    var data []int
    
    func readData() {
        rwMu.RLock() // Zaključavamo za čitanje
        // Čitanje data
        fmt.Println(data)
        rwMu.RUnlock() // Otključavamo čitanje
    }
    
    func writeData(val int) {
        rwMu.Lock() // Zaključavamo za zapis
        // Zapis u data
        data = append(data, val)
        rwMu.Unlock() // Otključavamo zapis
    }
    

Korišćenje mutexa je neophodno za sprečavanje stanja trke (race conditions), kada više gorutina istovremeno pokušava da modifikuje iste podatke, što može dovesti do nepredvidivih rezultata.

Pravila korišćenja:

  1. Pozovi Lock() pre pristupa zaštićenom resursu.
  2. Pozovi Unlock() nakon završetka pristupa. Preporučljivo je koristiti defer mu.Unlock() za garantovanje otključavanja čak i u slučaju panike.
  3. Ne pokušavaj da zaključavaš već zaključan mutex iz iste gorutine (može dovesti do deadlock-a).
  4. Ne pokušavaj da otključavaš nezaključan mutex.
  5. Kada koristiš RWMutex, koristi RLock/RUnlock za operacije čitanja i Lock/Unlock za operacije zapisivanja.
  6. Mutexi ne smeju da se kopiraju nakon prve upotrebe. Trebaju se prosleđivati po referenci ili pokazivaču.

Primer korišćenja defer:

func safeIncrement() {
    mu.Lock()
    defer mu.Unlock() // Garantuje otključavanje
    counter++
}