Cum se sincronizează datele între fire și se asigură coerența contextului?
sobes.tech AI
Răspuns de la AI
Pentru sincronizarea datelor și asigurarea coerenței contextului într-o aplicație multi-thread pe iOS, se folosesc următoarele abordări:
-
NSLock / Lock: Mutex-uri simple pentru blocarea secțiunilor critice de cod.
import Foundation class ThreadSafeCounter { private var count: Int = 0 private let lock = NSLock() func increment() { lock.lock() defer { lock.unlock() } // Garantarea deblocării count += 1 } func getCount() -> Int { lock.lock() defer { lock.unlock() } return count } } -
NSRecursiveLock: Permite reaplicarea blocării din același thread.
import Foundation class RecursiveLocker { private let lock = NSRecursiveLock() func firstMethod() { lock.lock() defer { lock.unlock() } print("Prima metodă") secondMethod() // Reaplicarea este posibilă } func secondMethod() { lock.lock() defer { lock.unlock() } print("A doua metodă") } } -
NSCondition / NSConditionLock: Permite firelor de execuție să aștepte o anumită condiție sau valoare înainte de a continua execuția. Este utilizat pentru implementarea pattern-ului producer-consumer.
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() // Așteaptă până când există spațiu liber } items.append(item) print("Adăugat: \(item), Buffer curent: \(items)") condition.signal() // Semnalează firele de execuție care așteaptă } func removeItem() -> Int { condition.lock() defer { condition.unlock() } while items.isEmpty { condition.wait() // Așteaptă până când apare un element } let item = items.removeFirst() print("Eliminat: \(item), Buffer curent: \(items)") condition.signal() // Semnalează firele de execuție care așteaptă spațiu return item } } -
Grand Central Dispatch (GCD):
-
Serial Queues: Execută sarcini în mod secvențial, una câte una pe un anumit thread, asigurând accesul atomic la resurse.
-
Concurrent Queues cu Barrier Flags: Permite citirea în mod concurent, dar operațiile de scriere (write) se execută exclusiv. Aceasta implementează modelul de lock de citire-scriere.
import Foundation class ThreadSafeArray<Element> { private var array: [Element] = [] private let queue = DispatchQueue(label: "com.mycompany.threadsafearray", attributes: .concurrent) // Coadă concurentă func append(_ newElement: Element) { queue.async(flags: .barrier) { // Barrier pentru scriere self.array.append(newElement) } } func get(at index: Int) -> Element? { var result: Element? queue.sync { // Sync pentru citire (sau async, dacă ordinea citirii nu este importantă) if index < self.array.count { result = self.array[index] } } return result } }
-
-
Operații Core Data Context: Fiecare
NSManagedObjectContextare propriul său fir serial privat. Accesul la obiecte și la context trebuie să se facă doar din acest fir.import CoreData // Exemplu de salvare în contextul Core Data let context = // Context obținut context.perform { // Executare pe firul privat al contextului // Lucru cu obiecte Core Data aici do { try context.save() } catch { // Tratarea erorii } }
Alegerea metodei depinde de sarcina specifică și de cerințele de performanță. GCD cu cozi seriale sau cozi concurente cu bariere sunt adesea cele mai preferate datorită eficienței și ușurinței de utilizare. Pentru Core Data, folosiți întotdeauna metodele perform sau performAndWait.