Sobes.tech
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:

  1. Pozadinski thread se blokira i čeka da glavni thread izvrši poslati blok koda.
  2. 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).
  3. 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.