Sobes.tech
Middle+

Ποιο είναι το πιο χαρακτηριστικό παράδειγμα deadlock στο iOS που μπορείτε να αναφέρετε;

sobes.tech AI

Απάντηση από AI

Το πιο προφανές παράδειγμα deadlock στο iOS συμβαίνει όταν προσπαθείτε να ενημερώσετε το UI από ένα background thread χωρίς να χρησιμοποιήσετε ειδικούς μηχανισμούς.

// Αυτός ο κώδικας θα προκαλέσει deadlock ή crash (ανάλογα με την έκδοση iOS και το πλαίσιο)
// όταν καλείται από ένα thread που δεν είναι το κύριο
DispatchQueue.global().async {
    // Εκτελούμε κάποια εργασία στο παρασκήνιο...
    print("Εργασία στο παρασκήνιο σε εξέλιξη")

    // Προσπαθούμε να ενημερώσουμε το UI απευθείας από το background thread
    // Αυτό θα προκαλέσει εξαίρεση ή deadlock, καθώς το UIKit δεν είναι ασφαλές για threads
    DispatchQueue.main.syncが必要です!
    // Αυτό προστέθηκε για να δείξει το πρόβλημα, μην το κάνετε σε πραγματικό κώδικα!
    DispatchQueue.main.sync {
        // Προσπάθεια ενημέρωσης ενός label στο κύριο thread
        // Αλλά επειδή ήδη περιμένουμε συγχρονικά το κύριο thread, το οποίο είναι μπλοκαρισμένο
        // από το δικό μας μπλοκ αποστολής συγχρονικά, προκύπτει deadlock.
        print("Προσπάθεια ενημέρωσης του UI")
        // someLabel.text = "Ενημερώθηκε από το παρασκήνιο" // Παράδειγμα γραμμής που θα προκαλούσε το πρόβλημα
    }
    print("Εργασία στο παρασκήνιο ολοκληρώθηκε")
}

Εξήγηση:

Το UIKit (το framework για τη δημιουργία διεπαφών χρήστη στο iOS) δεν είναι ασφαλές για threads. Όλες οι λειτουργίες UI πρέπει να εκτελούνται αυστηρά στο κύριο thread (main thread).

Στο παραπάνω παράδειγμα, αν καλέσετε το μπλοκ DispatchQueue.main.sync { ... } από ένα background thread, τότε:

  1. Το background thread μπλοκάρεται και περιμένει να εκτελέσει το κύριο thread το μπλοκ που του έχει σταλεί.
  2. Το κύριο thread μπορεί να είναι απασχολημένο ή, πιο πιθανό σε αυτό το σενάριο, να περιμένει την ολοκλήρωση μιας λειτουργίας που θα έπρεπε να είχε ξεκινήσει από το background thread (αν και σε αυτό το παράδειγμα δεν συμβαίνει αυτό, η συγχρονική αποστολή στο κύριο thread από background thread ήδη αποτελεί πρόβλημα).
  3. Στην περίπτωση του sync, το background thread δεν μπορεί να ολοκληρώσει την εργασία του μέχρι το κύριο thread να εκτελέσει το μπλοκ που του έχει σταλεί. Αν το κύριο thread είναι ήδη μπλοκαρισμένο (π.χ. περιμένει την ολοκλήρωση μιας λειτουργίας στο background που με τη σειρά του περιμένει το κύριο thread, ή απλά είναι απασχολημένο), δημιουργείται ένας κυκλικός κύκλος αναμονής, δηλαδή deadlock.

Ορθή λύση:

Χρησιμοποιήστε ασύγχρονη αποστολή στο κύριο thread για την ενημέρωση του UI.

// Ορθή λύση: ενημέρωση UI ασύγχρονα στο κύριο thread
DispatchQueue.global().async {
    // Εκτελούμε κάποια εργασία στο παρασκήνιο...
    print("Εργασία στο παρασκήνιο σε εξέλιξη")

    // Αποστέλλουμε την ενημέρωση UI ασύγχρονα στο κύριο thread
    DispatchQueue.main.async {
        print("Ενημέρωση UI στο κύριο thread")
        // someLabel.text = "Ενημερώθηκε από το παρασκήνιο" // Σωστό σημείο για ενημέρωση UI
    }
    print("Εργασία στο παρασκήνιο ολοκληρώθηκε")
}

Εδώ, το background thread δεν μπλοκάρεται κατά την αποστολή του μπλοκ στο κύριο thread, επιτρέποντας τόσο την εργασία στο background όσο και το κύριο thread να λειτουργούν ανεξάρτητα, αποφεύγοντας το deadlock.