Sobes.tech
Junior

Goroutine ilə işləyərkən deadlock nədir?

sobes.tech Süni İntellekt

AI-dan cavab

Deadlock (ölü nöqtə) — iki və ya daha çox goroutine-in bir-birini gözləyərək bloklandığı vəziyyətdir və heç biri icra etməyə davam edə bilmir. Bu, ən çox mutexlər və ya kanallar ilə işləyərkən baş verir.

Deadlock nümunələri:

  1. Mutexlərin fərqli ardıcıllıqla bloklanması:

    // Mutexlərlə deadlock nümunəsi
    var mu1 sync.Mutex
    var mu2 sync.Mutex
    
    func goroutine1() {
        mu1.Lock() // mu1-i bloklayır
        time.Sleep(100 * time.Millisecond) // Bir az gözləyir
        mu2.Lock() // mu2-ni bloklamağa çalışır (goroutine2 tərəfindən tutulur)
        fmt.Println("goroutine1 mu2-ni əldə etdi")
        mu2.Unlock()
        mu1.Unlock()
    }
    
    func goroutine2() {
        mu2.Lock() // mu2-ni bloklayır
        time.Sleep(100 * time.Millisecond) // Bir az gözləyir
        mu1.Lock() // mu1-i bloklamağa çalışır (goroutine1 tərəfindən tutulur)
        fmt.Println("goroutine2 mu1-i əldə etdi")
        mu1.Unlock()
        mu2.Unlock()
    }
    

    Goroutine1 mu1-i blokladı və mu2-ni gözləyir. Goroutine2 mu2-ni blokladı və mu1-i gözləyir. Hər ikisi bloklanıb.

  2. Buffersiz kanalə göndəriş və qəbul edən olmadan:

    // Deadlock nümunəsi kanal ilə
    func main() {
        ch := make(chan int)
        //go func() { // Əgər oxumaq üçün goroutine başlamazsa, deadlock yaranar
        //	<-ch
        //}()
        ch <- 1 // Kanalə göndəriş, qəbul edən olmadan
        fmt.Println("Kanalə göndərildi") // Bu sətir çatmayacaq
    }
    

    Buffersiz kanala göndəriş, başqa bir goroutine oxumağa başlayana qədər bloklanır. Əgər qəbul edən yoxdursa, deadlock yaranır.

  3. Kanaldan qəbul, göndərən olmadan (bağlandıqdan və ya boş buffer ilə):

    // Kanalın bağlanması və boş buffer ilə oxumaqda deadlock nümunəsi
    func main() {
        ch := make(chan int, 1) // 1 elementli bufferli kanal
        ch <- 1 // Göndərildi
        close(ch) // Kanal bağlandı
        <-ch // 1 oxundu
        <-ch // Yenidən bağlanmış və boş kanaldan oxumağa cəhd - deadlock
    }
    

    Bağlanmış və boş olmayan kanaldan oxuma uğurlu olacaq. Bağlanmış və boş kanal və ya açıq, lakin boş kanal, göndərən olmadan bloklanmaya səbəb olur.

Golang-in çalışma vaxtı bəzi deadlock tiplərini aşkar edə bilər (məsələn, bütün bloklanmış goroutine-lər tək bir goroutine-dən alma və ya göndərmə gözləyirsə), və bu halda proqram "fatal error: all goroutines are asleep - deadlock!" mesajı ilə ani şəkildə dayanacaq. Ancaq, bütün deadlock-lər avtomatik olaraq aşkar edilə bilməz.

Deadlock-ları qarşısını almaq üçün:

  • Mutexlərin tutma ardıcıllığını davamlı saxlayın.
  • Hər bir buffersiz kanala göndərmə üçün uyğun bir qəbul olduğunu təmin edin və əksinə.
  • Lazım gələrsə, selectdefault və ya zaman aşımı ilə kanallarla işləyin.
  • Goroutine-lərin həyat dövrünü və kanalların bağlanmasını diqqətlə idarə edin.