Wie synchronisiert man Daten zwischen Threads und stellt die Konsistenz des Kontexts sicher?
sobes.tech KI
Antwort von AI
Zur Synchronisierung von Daten und zur Gewährleistung der Konsistenz des Kontexts in einer Multithread-Anwendung auf iOS werden die folgenden Ansätze verwendet:
-
NSLock / Lock: Einfache Mutex zum Sperren kritischer Codeabschnitte.
import Foundation class ThreadSafeCounter { private var count: Int = 0 private let lock = NSLock() func increment() { lock.lock() defer { lock.unlock() } // Garantierte Freigabe des Locks count += 1 } func getCount() -> Int { lock.lock() defer { lock.unlock() } return count } } -
NSRecursiveLock: Erlaubt, das Lock erneut vom selben Thread zu erwerben.
import Foundation class RecursiveLocker { private let lock = NSRecursiveLock() func firstMethod() { lock.lock() defer { lock.unlock() } print("Erste Methode") secondMethod() // Wiederholtes Erwerben ist möglich } func secondMethod() { lock.lock() defer { lock.unlock() } print("Zweite Methode") } } -
NSCondition / NSConditionLock: Ermöglichen es Threads, auf eine bestimmte Bedingung oder einen Wert zu warten, bevor sie fortfahren. Wird für das Producer-Consumer-Muster verwendet.
import Foundation class Buffer { private var items: [Int] = [] private let condition = NSCondition() private let capacity = 5 func addItem(_ item: Int) { condition.lock() defer { condition.unlock() } while items.count == capacity { condition.wait() // Warten, bis Platz frei wird } items.append(item) print("Hinzugefügt: \(item), Aktueller Buffer: \(items)") condition.signal() // Signalisieren an wartende Threads } func removeItem() -> Int { condition.lock() defer { condition.unlock() } while items.isEmpty { condition.wait() // Warten, bis ein Element vorhanden ist } let item = items.removeFirst() print("Entfernt: \(item), Aktueller Buffer: \(items)") condition.signal() // Signalisieren an wartende Threads return item } } -
Grand Central Dispatch (GCD):
-
Serial Queues: Führen Aufgaben sequenziell aus, jeweils eine auf einmal auf dem gleichen Thread, was den atomaren Zugriff auf Ressourcen gewährleistet.
-
Concurrent Queues mit Barrier Flags: Ermöglichen paralleles Lesen, aber Schreiboperationen (write) werden exklusiv ausgeführt. Dies implementiert ein Read-Write-Lock-Modell.
import Foundation class ThreadSafeArray<Element> { private var array: [Element] = [] private let queue = DispatchQueue(label: "com.mycompany.threadsafearray", attributes: .concurrent) // Concurrency-Queue func append(_ newElement: Element) { queue.async(flags: .barrier) { // Barrier für Schreibzugriffe self.array.append(newElement) } } func get(at index: Int) -> Element? { var result: Element? queue.sync { // Synchronisation für Lesezugriffe (oder async, wenn Reihenfolge nicht wichtig ist) if index < self.array.count { result = self.array[index] } } return result } }
-
-
Core Data Context-Operationen: Jeder
NSManagedObjectContexthat seinen eigenen privaten serialisierten Thread. Der Zugriff auf Objekte und den Kontext sollte nur von diesem Thread erfolgen.import CoreData // Beispiel für das Speichern im Core Data-Kontext let context = // Erhaltener Kontext context.perform { // Ausführung im privaten Thread des Kontexts // Arbeit mit Core Data-Objekten hier do { try context.save() } catch { // Fehlerbehandlung } }
Die Wahl der Methode hängt von der spezifischen Aufgabe und den Leistungsanforderungen ab. GCD mit serialisierten oder concurrenten Queues mit Barrieren ist oft die bevorzugte Methode wegen ihrer Effizienz und Benutzerfreundlichkeit. Für Core Data verwenden Sie immer die Methoden perform oder performAndWait.