Sobes.tech
Middle+

Aký je najvýraznejší príklad deadlocku v iOS, ktorý môžete uviesť?

sobes.tech AI

Odpoveď od AI

Najjasnejším príkladom deadlocku v iOS je pokus o aktualizáciu UI z pozadia bez použitia špeciálnych mechanizmov.

// Tento kód spôsobí deadlock alebo pád (v závislosti od verzie iOS a kontextu)
// pri volaní mimo hlavného vlákna
DispatchQueue.global().async {
    // Vykonávame určitú prácu na pozadí...
    print("Pozadová práca sa vykonáva")

    // Pokúsime sa aktualizovať UI priamo z pozadia
    // To spôsobí výnimku alebo deadlock, pretože UIKit nie je vlákno-bezpečný
    DispatchQueue.main.syncが必要です!
    // Toto je pridané na demonštráciu problému - v reálnom kóde to robiť nemožno!
    DispatchQueue.main.sync {
        // Pokus o aktualizáciu štítku na hlavnom vlákne
        // Ale pretože už synchronne čakáme na hlavné vlákno, ktoré je zablokované
        // našim vlastným synchronným blokom odoslania, vzniká deadlock.
        print("Pokus o aktualizáciu UI")
        // someLabel.text = "Aktualizované z pozadia" // Príklad riadku, ktorý by spôsobil problém
    }
    print("Pozadová práca ukončená")
}

Vysvetlenie:

UIKit (framework pre tvorbu používateľského rozhrania v iOS) nie je vlákno-bezpečný. Všetky operácie s UI musia byť vykonávané striktné na hlavnom vlákne (main thread).

V uvedenom príklade, ak zavoláte blok DispatchQueue.main.sync { ... } z pozadia, tak:

  1. Pozadie vlákno sa zablokuje a čaká, kým hlavné vlákno vykoná odoslaný blok kódu.
  2. Hlavné vlákno v tomto čase môže byť zaneprázdnené, alebo, čo je pravdepodobnejšie v tomto scenári, samo čaká na dokončenie nejakej operácie, ktorá mala byť spustená z pozadia (hoci v tomto konkrétnom príklade toho nie je, synchronné odoslanie na hlavné vlákno z pozadia je problémom).
  3. V prípade sync sa pozadie vlákno nemôže dokončiť, kým hlavné vlákno ne vykoná predaný blok. Ak je hlavné vlákno už zablokované (napríklad čaká na dokončenie operácie v pozadí, ktorá zase čaká na hlavné vlákno, alebo je jednoducho zaneprázdnené), vzniká cyklické čakanie, teda deadlock.

Správne riešenie:

Použiť asynchrónne odoslanie na hlavný vlákno pre aktualizáciu UI.

// Správne riešenie: aktualizácia UI asynchrónne na hlavnom vlákne
DispatchQueue.global().async {
    // Vykonávame určitú prácu na pozadí...
    print("Pozadová práca sa vykonáva")

    // Odosielame aktualizáciu UI asynchrónne na hlavné vlákno
    DispatchQueue.main.async {
        print("Aktualizujeme UI na hlavnom vlákne")
        // someLabel.text = "Aktualizované z pozadia" // Správne miesto pre aktualizáciu UI
    }
    print("Pozadová práca ukončená")
}

Tu pozadie vlákno nie je zablokované pri odoslaní bloku na hlavné vlákno, čo umožňuje ako pozadie, tak hlavné vlákno pracovať nezávisle, čím sa vyhýbame deadlocku.