Middle+
Mi a legfeltűnőbb deadlock példa az iOS-ben, amit meg tudna nevezni?
sobes.tech MI
Válasz az MI-től
A legnyilvánvalóbb példa a deadlock-ra az iOS-ben akkor fordul elő, amikor megpróbálod frissíteni a UI-t háttérszálról anélkül, hogy speciális mechanizmusokat használnál.
// Ez a kód deadlock-ot vagy összeomlást okoz (az iOS verziójától és a kontextustól függően)
// amikor nem fő szálról hívják
DispatchQueue.global().async {
// Valamilyen háttérmunkát végzünk...
print("Háttérmunka folyamatban")
// Megpróbáljuk közvetlenül frissíteni a UI-t a háttérszálról
// Ez kivételt vagy deadlock-ot okoz, mivel a UIKit nem szálbiztos
DispatchQueue.main.syncが必要です!
// Ez hozzá lett adva a probléma demonstrálására, ne csináld ezt valódi kódban!
DispatchQueue.main.sync {
// Próbálkozás egy címke frissítésével a fő szálon
// De mivel már szinkron módon várunk a fő szálra, ami blokkolva van
// saját szinkron küldő blokkunk által, deadlock keletkezik.
print("UI frissítése próbálkozás")
// someLabel.text = "Háttérről frissítve" // Példasor, ami problémát okozna
}
print("Háttérmunka befejeződött")
}
Magyarázat:
A UIKit (az iOS felhasználói felületének építésére szolgáló keretrendszer) nem szálbiztos. Minden UI műveletet szigorúan a fő szálon kell végrehajtani.
A fenti példában, ha a DispatchQueue.main.sync { ... } blokkot háttérszálról hívod, akkor:
- A háttérszál blokkolódik, és vár, hogy a fő szál végrehajtsa a neki küldött blokkot.
- A fő szál lehet, hogy elfoglalt vagy, vagy, ami valószínűbb ebben a szcenárióban, vár egy olyan művelet befejezésére, amit a háttérszálról kellett volna indítani (bár ebben a példában nem így van, a szinkron küldés a fő szálra már problémás).
- A
syncesetén a háttérszál nem tud befejezni, amíg a fő szál nem hajtja végre a küldött blokkot. Ha a fő szál már blokkolva van (például egy háttérben futó művelet befejezését várja, ami viszont a fő szálat várja, vagy egyszerűen elfoglalt), ciklikus várakozás, azaz deadlock keletkezik.
Helyes megoldás:
Használj aszinkron küldést a fő szálra a UI frissítéséhez.
// Helyes megoldás: aszinkron UI frissítés a fő szálon
DispatchQueue.global().async {
// Valamilyen háttérmunkát végzünk...
print("Háttérmunka folyamatban")
// Aszinkron küldés a fő szálra a UI frissítéséhez
DispatchQueue.main.async {
print("UI frissítése a fő szálon")
// someLabel.text = "Háttérről frissítve" // Hely a UI frissítéséhez
}
print("Háttérmunka befejeződött")
}
Ebben az esetben a háttérszál nem blokkolódik a blokk küldése közben a fő szálra, lehetővé téve mind a háttérfeladat, mind a fő szál független működését, így elkerülve a deadlock-ot.