Sobes.tech
Middle+

Wat is het meest opvallende voorbeeld van een deadlock in iOS dat u kunt noemen?

sobes.tech AI

Antwoord van AI

Het meest duidelijke voorbeeld van deadlock in iOS doet zich voor wanneer je probeert de UI bij te werken vanuit een achtergrondthread zonder speciale mechanismen te gebruiken.

// Deze code zal een deadlock of crash veroorzaken (afhankelijk van de iOS-versie en context)
// wanneer deze wordt aangeroepen vanuit een niet-hoofdthread
DispatchQueue.global().async {
    // Voer wat achtergrondwerk uit...
    print("Achtergrondwerk gaande")

    // Probeer de UI direct bij te werken vanuit de achtergrondthread
    // Dit zal een uitzondering of deadlock veroorzaken, omdat UIKit niet thread-safe is
    DispatchQueue.main.syncが必要です!
    // Dit is toegevoegd om het probleem te demonstreren, doe dit niet in echte code!
    DispatchQueue.main.sync {
        // Probeer een label bij te werken op de hoofdthread
        // Maar omdat we al synchron wachten op de hoofdthread, die geblokkeerd is
        // door onze eigen synchronische verzendblok, ontstaat er een deadlock.
        print("Proberen UI bij te werken")
        // someLabel.text = "Bijgewerkt vanuit achtergrond" // Voorbeeldregel die het probleem zou veroorzaken
    }
    print("Achtergrondwerk voltooid")
}

Uitleg:

UIKit (het framework voor het bouwen van gebruikersinterfaces in iOS) is niet thread-safe. Alle UI-operaties moeten strikt op de hoofdthread worden uitgevoerd.

In het bovenstaande voorbeeld, als je het blok DispatchQueue.main.sync { ... } aanroept vanuit een achtergrondthread, dan:

  1. Wordt de achtergrondthread geblokkeerd en wacht tot de hoofdthread het verzonden blok uitvoert.
  2. Kan de hoofdthread bezig zijn of, in dit scenario, wachten op de voltooiing van een operatie die vanaf de achtergrondthread had moeten worden gestart (hoewel in dit voorbeeld niet het geval, het synchronisch verzenden naar de hoofdthread vanuit een achtergrondthread is al problematisch).
  3. In het geval van sync, kan de achtergrondthread zijn werk niet voltooien totdat de hoofdthread het verzonden blok heeft uitgevoerd. Als de hoofdthread al geblokkeerd is (bijvoorbeeld, wachtend op de voltooiing van een operatie in de achtergrond die op zijn beurt wacht op de hoofdthread, of gewoon bezet), ontstaat er een cyclische wacht, oftewel deadlock.

Correcte oplossing:

Gebruik asynchrone verzending naar de hoofdthread om de UI bij te werken.

// Correcte oplossing: update de UI asynchroon op de hoofdthread
DispatchQueue.global().async {
    // Voer wat achtergrondwerk uit...
    print("Achtergrondwerk gaande")

    // Verzend de UI-update asynchroon naar de hoofdthread
    DispatchQueue.main.async {
        print("UI wordt op de hoofdthread bijgewerkt")
        // someLabel.text = "Bijgewerkt vanuit achtergrond" // Juiste plek voor UI-updates
    }
    print("Achtergrondwerk voltooid")
}

Hier wordt de achtergrondthread niet geblokkeerd bij het verzenden van de blok naar de hoofdthread, waardoor zowel de achtergrondtaak als de hoofdthread onafhankelijk kunnen werken en deadlock wordt voorkomen.