Sobes.tech
Middle

Kas yra mutex, kokie tipai mutexų egzistuoja ir kaip juos naudoti?

sobes.tech AI

Atsakymas iš AI

Mūtas (iš anglų kalbos MUTual EXclusion) — tai sinchronizacijos primityvas, naudojamas užtikrinti išskirtinį prieigą prie bendro ištekliaus tarp konkuruojančių gorutinų. Jis garantuoja, kad bet kuriuo momentu tik viena gorutina gali turėti mūta ir atitinkamai naudotis saugomais duomenimis.

Go paketas sync siūlo du pagrindinius mūta tipus:

  • sync.Mutex: Standartinis mūtas. Pateikia Lock() ir Unlock() metodus. Jei mūtas jau užrakintas, Lock() kvietimas blokuoja dabartinę gorutina, kol jis nebus atlaisvintas. Unlock() atlaisvina mūta.

    var mu sync.Mutex
    var counter int
    
    func increment() {
        mu.Lock() // Užrakinti prieigą prie counter
        counter++
        mu.Unlock() // Atlaisvinti prieigą
    }
    
  • sync.RWMutex: Skaitymo/rašymo mūtas. Leidžia kelioms gorutinoms vienu metu skaityti saugomą išteklį, bet tik vienai rašyti. Pateikia Lock(), Unlock() (rašymui), RLock() ir RUnlock() (skaitymui) metodus.

    var rwMu sync.RWMutex
    var data []int
    
    func readData() {
        rwMu.RLock() // Užrakinti skaitymui
        // Skaityti data
        fmt.Println(data)
        rwMu.RUnlock() // Atlaisvinti skaitymą
    }
    
    func writeData(val int) {
        rwMu.Lock() // Užrakinti rašymui
        // Rašyti į data
        data = append(data, val)
        rwMu.Unlock() // Atlaisvinti rašymą
    }
    

Mūta naudojimas yra būtinas norint išvengti lenktynių sąlygų, kai keli gorutinai vienu metu bando modifikuoti tas pačias duomenų dalis, kas gali sukelti nenuspėjamus rezultatus.

Naudojimo taisyklės:

  1. Kviesti Lock() prieš prieigą prie saugomo ištekliaus.
  2. Kviesti Unlock() po prieigos pabaigos. Rekomenduojama naudoti defer mu.Unlock() garantijai, kad išlaisvinimas įvyks net ir panikos atveju.
  3. Negalima pakartotinai užrakinti jau užrakintą mūta iš tos pačios gorutinos (gali sukelti deadlock).
  4. Negalima atlaisvinti neužrakinto mūta.
  5. Naudojant RWMutex, naudokite RLock/RUnlock skaitymo operacijoms ir Lock/Unlock rašymo operacijoms.
  6. Mūta neturėtų būti kopijuojami po pirmojo naudojimo. Juos perduokite nuoroda arba rodykle.

Pavyzdys naudojant defer:

func safeIncrement() {
    mu.Lock()
    defer mu.Unlock() // Garantuoja atlaisvinimą
    counter++
}