Sobes.tech
Junior

Mis on deadlock, töötades goroutine'iga?

sobes.tech AI

Vastus AI-lt

Deadlock (sulg) — see olukord, kus kaks või rohkem gorutinit blokeerivad üksteist, oodates teineteist, ning ükski neist ei saa jätkata täitmist. Kõige sagedamini tekib see mutexide või kanalite kasutamisel.

Deadlocki näited:

  1. Mutexide lukustamine erinevas järjekorras:

    // Deadlocki näide mutexidega
    var mu1 sync.Mutex
    var mu2 sync.Mutex
    
    func goroutine1() {
        mu1.Lock() // Lukustab mu1
        time.Sleep(100 * time.Millisecond) // Väike ooteaeg
        mu2.Lock() // Püüab lukustada mu2 (mida hoiab goroutine2)
        fmt.Println("goroutine1 saavutas mu2")
        mu2.Unlock()
        mu1.Unlock()
    }
    
    func goroutine2() {
        mu2.Lock() // Lukustab mu2
        time.Sleep(100 * time.Millisecond) // Väike ooteaeg
        mu1.Lock() // Püüab lukustada mu1 (mida hoiab goroutine1)
        fmt.Println("goroutine2 saavutas mu1")
        mu1.Unlock()
        mu2.Unlock()
    }
    

    Goroutine1 saavutas mu1 ja ootab mu2. Goroutine2 saavutas mu2 ja ootab mu1. Mõlemad gorutined on blokeeritud.

  2. Saatmine mittebuferiseeritud kanalile ilma vastuvõtja without:

    // Deadlocki näide kanali kasutamisel
    func main() {
        ch := make(chan int)
        //go func() { // Kui me ei käivita lugemis-gorutinit, tekib deadlock
        //	<-ch
        //}()
        ch <- 1 // Saatmine kanalile ilma aktiivse vastuvõtjata
        fmt.Println("Saadetud kanalile") // See rida ei jõua täide
    }
    

    Saatmine mittebuferiseeritud kanalile blokeerib kuni teine gorutina hakkab sellest lugema. Kui vastuvõtjat pole, tekib deadlock.

  3. Lugemine kanalilt ilma saatjata (pärast sulgemist või tühja bufferit):

    // Deadlocki näide kanali lugemisel
    func main() {
        ch := make(chan int, 1) // Bufferiga kanal 1 elemendiga
        ch <- 1 // Saatsime 1
        close(ch) // Sulgesime kanali
        <-ch // Lugesime 1
        <-ch // Püüame uuesti lugeda suletud ja tühjast kanalist - deadlock
    }
    

    Lugemine suletud, tühjast või avatud, kuid tühjast mittebuferiseeritud kanalist ilma saatjata põhjustab blokeeringu.

Golangi jooksukeskkond suudab tuvastada teatud deadlock-tüüpe (näiteks, kui kõik blokeeritud gorutined ootavad ühe gorutina vastuvõtu või saatmise lõpetamist), ning sellisel juhul lõpetab programm ootamatult sõnumiga "fatal error: all goroutines are asleep - deadlock!". Kuid mitte kõik deadlockid ei pruugi automaatselt tuvastada.

Deadlockide ennetamiseks on oluline:

  • Säilitada järjepidev mutexide lukustamise järjekord.
  • Tagada, et iga mittebuferiseeritud saatmisele vastab sobiv lugemine, ja vastupidi.
  • Kanalitega töötades kasutada select koos default haruga või ajapiiranguid vastavalt vajadusele.
  • Hoolikalt hallata gorutinate elutsüklit ja kanalite sulgemist.