Ako synchronizovať údaje medzi vláknami a zabezpečiť konzistentnosť kontextu?
sobes.tech AI
Odpoveď od AI
Na synchronizáciu údajov a zabezpečenie konzistencie kontextu v viacvláknovej aplikácii na iOS sa používajú nasledujúce prístupy:
-
NSLock / Lock: Jednoduché mutexy na blokovanie kritických sekcií kódu.
import Foundation class ThreadSafeCounter { private var count: Int = 0 private let lock = NSLock() func increment() { lock.lock() defer { lock.unlock() } // Zaručené odblokovanie count += 1 } func getCount() -> Int { lock.lock() defer { lock.unlock() } return count } } -
NSRecursiveLock: Umožňuje opätovne získať zámok z toho istého vlákna.
import Foundation class RecursiveLocker { private let lock = NSRecursiveLock() func firstMethod() { lock.lock() defer { lock.unlock() } print("Prvá metóda") secondMethod() // Opätovné získanie je možné } func secondMethod() { lock.lock() defer { lock.unlock() } print("Druhá metóda") } } -
NSCondition / NSConditionLock: Umožňuje vláknam čakať na určitú podmienku (Condition) alebo hodnotu (ConditionLock) pred pokračovaním vo vykonávaní. Používa sa na implementáciu producer-consumer vzoru.
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() // Čaká, kým sa neuvoľní miesto } items.append(item) print("Pridané: \(item), Aktuálny buffer: \(items)") condition.signal() // Signalizuje čakajúcim vláknam } func removeItem() -> Int { condition.lock() defer { condition.unlock() } while items.isEmpty { condition.wait() // Čaká, kým sa neobjaví prvok } let item = items.removeFirst() print("Odstránené: \(item), Aktuálny buffer: \(items)") condition.signal() // Signalizuje čakajúcim vláknam return item } } -
**Grand Central Dispatch (GCD):
-
Serial Queues: Vykonávajú úlohy postupne, po jednej naraz na danom vlákne, čo zabezpečuje atómovosť prístupu ku zdrojom.
-
Concurrent Queues s Barrier Flags: Umožňujú vykonávať čítanie súbežne, ale zápisové operácie (write) sa vykonávajú exkluzívne. Toto implementuje model read-write lock.
import Foundation class ThreadSafeArray<Element> { private var array: [Element] = [] private let queue = DispatchQueue(label: "com.mycompany.threadsafearray", attributes: .concurrent) // Súbežná fronta func append(_ newElement: Element) { queue.async(flags: .barrier) { // Barrier pre zápis self.array.append(newElement) } } func get(at index: Int) -> Element? { var result: Element? queue.sync { // Synchronizácia pre čítanie (alebo async, ak poradie čítania nie je dôležité) if index < self.array.count { result = self.array[index] } } return result } }
-
-
Operácie Core Data Context: Každý
NSManagedObjectContextmá vlastný súkromný serializovaný vlákno. Prístup k objektom a kontextu by sa mal vykonávať iba z tohto vlákna.import CoreData // Príklad uloženia do Core Data kontextu let context = // Získaný kontext context.perform { // Vykonanie na súkromnom vlákne kontextu // Práca s objektmi Core Data do { try context.save() } catch { // Spracovanie chyby } }
Voľba metódy závisí od konkrétnej úlohy a požiadaviek na výkon. GCD s radovými frontami alebo súbežnými frontami s bariérami je často najpreferovanejšou voľbou kvôli svojej efektívnosti a jednoduchosti použitia. Pre Core Data nevyhnutne používajte metódy perform alebo performAndWait.