Sobes.tech
Middle

Πώς συγχρονίζονται τα δεδομένα μεταξύ νημάτων (πλαισίου) στο iOS;

sobes.tech AI

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

Για συγχρονισμό, μπορούν να χρησιμοποιηθούν οι ακόλουθοι μηχανισμοί:

  1. NSLock: Ένα απλό μπλοκαριστικό mutex.

    let lock = NSLock()
    
    func doSomething() {
        lock.lock()
        // Κρίσιμη ενότητα κώδικα
        lock.unlock()
    }
    
  2. NSRecursiveLock: Επιτρέπει σε ένα νήμα να αποκτήσει ξανά το κλείδωμα χωρίς deadlock.

    let recursiveLock = NSRecursiveLock()
    
    func recursiveFunction(level: Int) {
        recursiveLock.lock()
        if level < 3 {
            recursiveFunction(level: level + 1)
        }
        recursiveLock.unlock()
    }
    
  3. NSCondition: Επιτρέπει στα νήματα να περιμένουν μια συγκεκριμένη συνθήκη πριν συνεχίσουν.

    let condition = NSCondition()
    var dataAvailable = false
    
    func producer() {
        condition.lock()
        // Παραγωγή δεδομένων
        dataAvailable = true
        condition.signal() // Σήμα στα αναμένοντα νήματα
        condition.unlock()
    }
    
    func consumer() {
        condition.lock()
        while !dataAvailable {
            condition.wait() // Περιμένει μέχρι να εκπληρωθεί η συνθήκη
        }
        // Επεξεργασία δεδομένων
        dataAvailable = false
        condition.unlock()
    }
    
  4. NSConditionLock: Ένα mutex που μπορεί να κρατηθεί μόνο αν μια συγκεκριμένη τιμή συνθήκης ισχύει.

    let conditionLock = NSConditionLock(condition: 0)
    let DATA_READY = 1
    
    func producer() {
        conditionLock.lock(when: 0) // Κλείδωμα όταν η συνθήκη είναι 0
        // Παραγωγή δεδομένων
        conditionLock.unlock(withCondition: DATA_READY) // Ξεκλείδωμα και ρύθμιση της συνθήκης σε DATA_READY
    }
    
    func consumer() {
        conditionLock.lock(when: DATA_READY) // Κλείδωμα όταν η συνθήκη είναι DATA_READY
        // Επεξεργασία δεδομένων
        conditionLock.unlock(withCondition: 0) // Ξεκλείδωμα και ρύθμιση της συνθήκης σε 0
    }
    
  5. Dispatch Queues (GCD): Χρήση διαδοχικών ουρών dispatch για πρόσβαση σε κοινόχρηστους πόρους.

    let serialQueue = DispatchQueue(label: "com.yourapp.serialQueue")
    var sharedResource = 0
    
    func updateResource() {
        serialQueue.async {
            // Πρόσβαση στο sharedResource μόνο από αυτήν την ουρά
            sharedResource += 1
        }
    }
    
  6. NSOperationQueue: Επιτρέπει τον έλεγχο των εξαρτήσεων και των προτεραιοτήτων των λειτουργιών.

    let operationQueue = OperationQueue()
    var sharedOperationResource = 0
    
    let operation1 = BlockOperation {
        // Πρόσβαση στο sharedOperationResource
        sharedOperationResource += 1
    }
    
    operationQueue.addOperation(operation1)
    
  7. Actors (Swift 5.5+): Παρέχουν απομόνωση κατάστασης, αποτρέποντας ταυτόχρονη πρόσβαση από διαφορετικά συμφραζόμενα.

    actor Counter {
        private var count = 0
    
        func increment() {
            count += 1
        }
    
        func getCount() -> Int {
            return count
        }
    }
    
    let counter = Counter()
    
    Task {
        await counter.increment()
        let currentCount = await counter.getCount()
        print(currentCount)
    }
    
  8. Core Data Contexts: Για συγχρονισμό των context δεδομένων, μπορούν να χρησιμοποιηθούν ιεραρχικά contexts (γονέας-απόγονος) ή mergeChanges(fromContextDidSaveNotification:).

    // Παράδειγμα με ιεραρχία (γονέας - φόντο, παιδί - UI)
    let privateMoc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
    privateMoc.persistentStoreCoordinator = persistentStoreCoordinator
    
    let mainMoc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    mainMoc.parent = privateMoc
    
    // Παράδειγμα με mergeChanges
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(contextDidSave(_:)),
                                           name: .NSManagedObjectContextDidSave,
                                           object: nil)
    
    @objc func contextDidSave(_ notification: Notification) {
        guard let savingContext = notification.object as? NSManagedObjectContext else { return }
    
        if savingContext != mainMoc { // Αν η αποθήκευση έγινε σε άλλο context
            mainMoc.perform {
                mainMoc.mergeChanges(fromContextDidSave: notification)
            }
        }
    }
    
  9. Ατομικές λειτουργίες: Χρήση ατομικών primitive (π.χ. από os/lock.h) για απλές λειτουργίες.

Η επιλογή της μεθόδου εξαρτάται από την πολυπλοκότητα της εργασίας, τον τύπο των δεδομένων και τις απαιτήσεις απόδοσης. Οι Actors και GCD είναι σύγχρονες προσεγγίσεις που προτιμώνται.