Sobes.tech
Junior

Goroutine ile çalışırken deadlock nedir?

sobes.tech yapay zeka

AI'dan gelen yanıt

Deadlock (ölü nokta), iki veya daha fazla goroutine'un birbirini bekleyerek kilitlendiği ve hiç birinin çalışmaya devam edemediği bir durumdur. En sık mutexler veya kanallar kullanılırken ortaya çıkar.

Deadlock örnekleri:

  1. Farklı sırayla mutex kilitleme:

    // Mutexlerle deadlock örneği
    var mu1 sync.Mutex
    var mu2 sync.Mutex
    
    func goroutine1() {
        mu1.Lock() // mu1 kilitleniyor
        time.Sleep(100 * time.Millisecond) // Biraz bekliyor
        mu2.Lock() // mu2'yi kilitlemeye çalışıyor (goroutine2 tarafından tutuluyor)
        fmt.Println("goroutine1 mu2'yi edindi")
        mu2.Unlock()
        mu1.Unlock()
    }
    
    func goroutine2() {
        mu2.Lock() // mu2'yi kilitliyor
        time.Sleep(100 * time.Millisecond) // Biraz bekliyor
        mu1.Lock() // mu1'yi kilitlemeye çalışıyor (goroutine1 tarafından tutuluyor)
        fmt.Println("goroutine2 mu1'i edindi")
        mu1.Unlock()
        mu2.Unlock()
    }
    

    Goroutine1 mu1'i kilitledi ve mu2'yi bekliyor. Goroutine2 mu2'yi kilitledi ve mu1'i bekliyor. Her ikisi de kilitli durumda.

  2. Tüketici olmadan buffer olmayan kanala gönderim:

    // Deadlock örneği kanal ile
    func main() {
        ch := make(chan int)
        //go func() { // Okuma yapan bir goroutine başlatılmazsa deadlock olur
        //	<-ch
        //}()
        ch <- 1 // Aktif bir alıcı olmadan kanala gönderim
        fmt.Println("Kanal'a gönderildi") // Bu satıra ulaşılmaz
    }
    

    Buffer olmayan kanala gönderim, başka bir goroutine'den okuma başlamadan engellenir. Alıcı yoksa deadlock oluşur.

  3. Kapanmış veya boş buffer'lı kanaldan okuma:

    // Kapanmış kanaldan okuma sırasında deadlock
    func main() {
        ch := make(chan int, 1) // 1 elemanlı bufferli kanal
        ch <- 1 // Gönderildi
        close(ch) // Kanal kapatıldı
        <-ch // 1 okundu
        <-ch // Kapanmış ve boş kanaldan tekrar okuma - deadlock
    }
    

    Kapanmış ve boş olmayan kanaldan okuma başarılı olur. Kapanmış ve boş kanal veya açık ama boş kanal okuma blokajına neden olur.

Golang çalışma zamanı belirli deadlock türlerini tespit edebilir (örneğin, tüm kilitli goroutine'ler tek bir goroutine'den alma veya gönderme bekliyorsa), ve bu durumda program "fatal error: all goroutines are asleep - deadlock!" mesajıyla aniden sona erer. Ancak, tüm deadlock'lar otomatik olarak tespit edilemeyebilir.

Deadlock'u önlemek için:

  • Mutexleri tutarken tutarlı bir sıralama izlemek.
  • Buffer olmayan kanala her gönderim için uygun bir okuma olduğunu sağlamak ve tersi.
  • Gerekirse select kullanmak ve default veya zaman aşımı eklemek.
  • Goroutine'lerin yaşam süresini ve kanalların kapanmasını dikkatli yönetmek.