Sobes.tech
Middle

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ă metodele Lock() și Unlock(). Dacă mutex-ul este deja blocat, apelul Lock() 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ă metodele Lock(), Unlock() (pentru scriere), RLock() și RUnlock() (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:

  1. Apelați Lock() înainte de a accesa resursa protejată.
  2. Apelați Unlock() după ce ați terminat accesul. Se recomandă utilizarea defer mu.Unlock() pentru a garanta deblocarea chiar și în cazul panicii.
  3. Nu încercați să blocați un mutex deja blocat din aceeași gorutină (poate duce la deadlock).
  4. Nu încercați să deblocați un mutex neblocat.
  5. La utilizarea RWMutex, folosiți RLock/RUnlock pentru operațiuni de citire și Lock/Unlock pentru operațiuni de scriere.
  6. 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++
}