Ce este un mutex, ce tipuri de mutex-uri există și cum se folosesc?
sobes.tech AI
Răspuns de la AI
Mutex (din engleză MUTual EXclusion) este o primitive de sincronizare utilizată pentru a asigura accesul exclusiv la o resursă partajată între gorutine concurente. El garantează că, într-un moment dat, doar o gorutină poate deține mutex-ul și poate accesa datele protejate.
În Go, pachetul sync oferă două tipuri principale de mutex-uri:
-
sync.Mutex: Mutex standard. Oferă metodeleLock()șiUnlock(). Dacă mutex-ul este deja blocat, apelulLock()blochează gorutina curentă până când acesta este eliberat.Unlock()deblochează mutex-ul.var mu sync.Mutex var counter int func increment() { mu.Lock() // Blochează accesul la counter counter++ mu.Unlock() // Deblochează accesul } -
sync.RWMutex: Mutex pentru citire/scriere. Permite mai multor gorutine să citească simultan resursa protejată, dar doar uneia să scrie. Oferă metodeleLock(),Unlock()(pentru scriere),RLock()șiRUnlock()(pentru citire).var rwMu sync.RWMutex var data []int func readData() { rwMu.RLock() // Blochează pentru citire // Citește data fmt.Println(data) rwMu.RUnlock() // Deblochează citirea } func writeData(val int) { rwMu.Lock() // Blochează pentru scriere // Scrie în data data = append(data, val) rwMu.Unlock() // Deblochează scrierea }
Utilizarea mutexurilor este necesară pentru prevenirea condițiilor de cursă (race conditions), atunci când mai multe gorutine încearcă să modifice în același timp aceleași date, conducând la rezultate imprevizibile.
Reguli de utilizare:
- Apelați
Lock()înainte de a accesa resursa protejată. - Apelați
Unlock()după ce ați terminat accesul. Se recomandă utilizareadefer mu.Unlock()pentru a garanta deblocarea chiar și în cazul panicii. - Nu încercați să blocați un mutex deja blocat din aceeași gorutină (poate duce la deadlock).
- Nu încercați să deblocați un mutex neblocat.
- La utilizarea
RWMutex, folosițiRLock/RUnlockpentru operațiuni de citire șiLock/Unlockpentru operațiuni de scriere. - Mutexurile nu trebuie copiate după prima utilizare. Transmiteți-le prin referință sau pointer.
Exemplu de utilizare a defer:
func safeIncrement() {
mu.Lock()
defer mu.Unlock() // Garantează deblocarea
counter++
}