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:
- Pozadie vlákno sa zablokuje a čaká, kým hlavné vlákno vykoná odoslaný blok kódu.
- 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).
- V prípade
syncsa 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.