Sobes.tech
Junior

Goroutine bilan ishlashda deadlock nima?

sobes.tech AI

AIdan javob

Deadlock (o'lim) — bu holatda, ikki yoki undan ortiq gorutinalar bir-birini kutib, bloklanib qoladigan holat. Bu holat ko'proq mutexlar yoki kanallar bilan ishlashda yuzaga keladi.

Deadlock misollari:

  1. Mutexlarni turli tartibda bloklash:

    // Mutexlar bilan deadlock misoli
    var mu1 sync.Mutex
    var mu2 sync.Mutex
    
    func goroutine1() {
        mu1.Lock() // mu1 ni bloklaydi
        time.Sleep(100 * time.Millisecond) // Biroz kutadi
        mu2.Lock() // mu2 ni bloklamoqchi (goroutine2 tomonidan band)
        fmt.Println("goroutine1 mu2 ni egalladi")
        mu2.Unlock()
        mu1.Unlock()
    }
    
    func goroutine2() {
        mu2.Lock() // mu2 ni bloklaydi
        time.Sleep(100 * time.Millisecond) // Biroz kutadi
        mu1.Lock() // mu1 ni bloklamoqchi (goroutine1 tomonidan band)
        fmt.Println("goroutine2 mu1 ni egalladi")
        mu1.Unlock()
        mu2.Unlock()
    }
    

    Goroutine1 mu1 ni blokladi va mu2 ni kutmoqda. Goroutine2 mu2 ni blokladi va mu1 ni kutmoqda. Ikkalasi ham bloklangan.

  2. Buffersiz kanalga yuborish, qabul qiluvchi bo'lmagan holda:

    // Deadlock misoli kanal bilan
    func main() {
        ch := make(chan int)
        //go func() { // Agar o'qish uchun goroutine ishga tushirilmasa, deadlock yuzaga keladi
        //	<-ch
        //}()
        ch <- 1 // Kanalga yuborish, qabul qiluvchi bo'lmasa
        fmt.Println("Yuborildi kanalga") // Bu satrga yetib borilmaydi
    }
    

    Buffersiz kanalga yuborish, boshqa goroutine o'qishni boshlaguncha bloklanadi. Agar qabul qiluvchi bo'lmasa, deadlock yuzaga keladi.

  3. Kanaldan qabul qilish, yuboruvchi bo'lmagan holda (yopilgan yoki bo'sh buffer bilan):

    // Kanal yopilgan va bo'sh bo'lsa, o'qish deadlockga olib keladi
    func main() {
        ch := make(chan int, 1) // 1 elementli bufferli kanal
        ch <- 1 // Yuborildi
        close(ch) // Kanal yopildi
        <-ch // 1 o'qildi
        <-ch // Yopilgan va bo'sh kanalni yana o'qishga urinish - deadlock
    }
    

    Yopilgan va bo'sh bo'lmagan kanaldan o'qish muvaffaqiyatli bo'ladi. Yopilgan va bo'sh kanal yoki ochiq, ammo bo'sh kanal, yuboruvchi bo'lmagan holda, blokirovkaga olib keladi.

Golang runtime ba'zi deadlock turlarini aniqlay oladi (masalan, barcha bloklangan gorutinalar yagona goroutine'dan qabul qilish yoki yuborishni kutayotgan bo'lsa), va bu holatda dastur "fatal error: all goroutines are asleep - deadlock!" xabari bilan to'xtaydi. Biroq, barcha deadlocklar avtomatik tarzda aniqlanmaydi.

Deadlocklarni oldini olish uchun:

  • Mutexlarni tutishda ketma-ketlikni muvofiqlashtirish.
  • Har bir buffersiz kanalda yuborish uchun mos o'qish mavjudligini ta'minlash va aksincha.
  • Kerak bo'lsa, select va default yoki timeoutlardan foydalanish.
  • Gorutinalarning hayot davrini va kanallarni ehtiyotkorlik bilan boshqarish.