Middle+
Koji je najupadljiviji primer deadlock-a u iOS koji možete navesti?
sobes.tech АИ
Одговор од АИ
Najjasniji primer deadlock-a u iOS nastaje prilikom pokušaja ažuriranja UI iz pozadinskog toka bez korišćenja specijalnih mehanizama.
// Ovaj kod će izazvati deadlock ili pad (u zavisnosti od verzije iOS-a i konteksta)
// pri pozivu van glavnog toka
DispatchQueue.global().async {
// Izvršavamo neki rad u pozadini...
print("Pozadinski rad se izvršava")
// Pokušavamo da ažuriramo UI direktno iz pozadinskog toka
// To će izazvati izuzetak ili deadlock, jer UIKit nije bezbedan za rad sa nitima
DispatchQueue.main.syncが必要です!
// Ovo je dodato za demonstraciju problema - u realnom kodu to ne treba raditi!
DispatchQueue.main.sync {
// Pokušaj ažuriranja oznake na glavnom thread-u
// Ali jer već sinhrono čekamo na glavni thread, koji je blokiran
// našim sopstvenim sinhronim blokom slanja, javlja se deadlock.
print("Pokušaj ažuriranja UI")
// someLabel.text = "Ažurirano iz pozadine" // Primer linije koja bi izazvala problem
}
print("Pozadinski rad završen")
}
Objašnjenje:
UIKit (framework za pravljenje korisničkog interfejsa u iOS) nije bezbedan za rad sa nitima. Sve operacije sa UI-jem moraju biti izvršene strogo na glavnom thread-u (main thread).
U datom primeru, ako pozovete blok DispatchQueue.main.sync { ... } iz pozadinskog thread-a, tada:
- Pozadinski thread se blokira i čeka da glavni thread izvrši poslati blok koda.
- Glavni thread u tom trenutku može biti zauzet, ili, što je verovatnije, sam čeka na završetak neke operacije koja je trebala biti pokrenuta iz pozadinskog thread-a (iako u ovom konkretnom primeru toga nema, sinhrono slanje na glavni thread iz pozadinskog je problematično).
- U slučaju
sync, pozadinski thread ne može da završi dok glavni thread ne izvrši poslati blok. Ako je glavni thread već blokiran (npr. čeka na završetak operacije u pozadinskom thread-u, koji opet čeka na glavni thread, ili je jednostavno zauzet), dolazi do cikličkog čekanja, odnosno deadlock.
Pravo rešenje:
Koristiti asinhrono slanje na glavni thread za ažuriranje UI.
// Pravo rešenje: ažuriranje UI asinhrono na glavnom thread-u
DispatchQueue.global().async {
// Izvršavamo neki rad u pozadini...
print("Pozadinski rad se izvršava")
// Šaljemo ažuriranje UI asinhrono na glavni thread
DispatchQueue.main.async {
print("Ažuriramo UI na glavnom thread-u")
// someLabel.text = "Ažurirano iz pozadine" // Pravo mesto za ažuriranje UI
}
print("Pozadinski rad završen")
}
Ovde pozadinski thread nije blokiran prilikom slanja bloka na glavni thread, omogućavajući i pozadinskom zadatku i glavnom thread-u da rade nezavisno, čime se izbegava deadlock.