Sobes.tech
Middle+

Kāds ir spilgtākais deadlock piemērs iOS, ko varat minēt?

sobes.tech AI

Atbilde no AI

Visizteiktākais piemērs deadlock iOS gadījumā ir mēģinājums atjaunināt UI no fonu pavediena bez speciālu mehānismu izmantošanas.

// Šis kods radīs deadlock vai avāriju (atkarībā no iOS versijas un konteksta)
// izsaucot to ārpus galvenā pavediena
DispatchQueue.global().async {
    // Veicam kādu fonu darbu...
    print("Fona darbs notiek")

    // Mēģinām tieši atjaunināt UI no fonu pavediena
    // Tas radīs izņēmumu vai deadlock, jo UIKit nav pavedienu drošs
    DispatchQueue.main.syncが必要です!
    // Tas ir pievienots, lai demonstrētu problēmu - reālā kodā tā nedrīkst darīt!
    DispatchQueue.main.sync {
        // Mēģinājums atjaunināt zīmi galvenajā pavedienā
        // Bet, jo mēs jau sinhroni gaidām galveno pavedienu, kas ir bloķēts
        // ar paša sinhronās sūtīšanas bloku, rodas deadlock.
        print("Mēģinājums atjaunināt UI")
        // someLabel.text = "Atjaunināts no fona" // Piemērs rindai, kas radīs problēmu
    }
    print("Fona darbs pabeigts")
}

Skaidrojums:

UIKit (rāmis lietotāja saskarnes veidošanai iOS) nav pavedienu drošs. Visas darbības ar UI ir jāveic stingri galvenajā pavedienā (main thread).

Iepriekšējā piemērā, ja izsaucat DispatchQueue.main.sync { ... } bloku no fonu pavediena, tad:

  1. Fonu pavediens tiks bloķēts un gaidīs, kamēr galvenais pavedienu izpildīs nosūtīto bloku.
  2. Galvenais pavedienu tajā laikā var būt aizņemts vai, kas ir ticamāk, pats gaida, kamēr pabeigs kādu operāciju, kas būtu jāuzsāk no fonu pavediena (lai gan šajā konkrētajā piemērā tas nav, sinhrona sūtīšana uz galveno pavedienu no fonu pavediena jau ir problēma).
  3. sync gadījumā, fonu pavedienu nevar pabeigt, kamēr galvenais pavedienu neizpildīs nosūtīto bloku. Ja galvenais pavedienu jau ir bloķēts (piemēram, gaida, kamēr pabeigs fonu pavediena operāciju, kas savukārt gaida galveno pavedienu, vai vienkārši ir aizņemts), rodas ciklisks gaidīšanas process, t.i., deadlock.

Pareizais risinājums:

Izmantot asimetrisku sūtīšanu uz galveno pavedienu UI atjaunināšanai.

// Pareizais risinājums: UI atjaunināšana asimetriski galvenajā pavedienā
DispatchQueue.global().async {
    // Veicam kādu fonu darbu...
    print("Fona darbs notiek")

    // Nosūtām UI atjaunināšanu asimetriski uz galveno pavedienu
    DispatchQueue.main.async {
        print("Atjauninām UI galvenajā pavedienā")
        // someLabel.text = "Atjaunināts no fona" // Pareizā vieta UI atjaunināšanai
    }
    print("Fona darbs pabeigts")
}

Šeit fonu pavedienu netraucē nosūtīt bloku uz galveno pavedienu, ļaujot gan fonu, gan galveno pavedienu darboties neatkarīgi, novēršot deadlock.