Kako sinhronizovati podatke između niti i obezbediti konzistentnost konteksta?
sobes.tech АИ
Одговор од АИ
Za sinhronizaciju podataka i obezbeđivanje konzistentnosti konteksta u višestrukom nitnom okruženju na iOS-u koriste se sledeći pristupi:
-
NSLock / Lock: Jednostavni mutexi za blokiranje kritičnih sekcija koda.
import Foundation class ThreadSafeCounter { private var count: Int = 0 private let lock = NSLock() func increment() { lock.lock() defer { lock.unlock() } // Garantovano otpuštanje blokade count += 1 } func getCount() -> Int { lock.lock() defer { lock.unlock() } return count } } -
NSRecursiveLock: Omogućava višestruko zaključavanje iz istog niti.
import Foundation class RecursiveLocker { private let lock = NSRecursiveLock() func firstMethod() { lock.lock() defer { lock.unlock() } print("Prva metoda") secondMethod() // Moguće je višestruko zaključavanje } func secondMethod() { lock.lock() defer { lock.unlock() } print("Druga metoda") } } -
NSCondition / NSConditionLock: Omogućava nitima da čekaju određeni uslov (Condition) ili vrednost (ConditionLock) pre nastavka izvršavanja. Koristi se za implementaciju producer-consumer obrasca.
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() // Čeka dok se ne oslobodi mesto } items.append(item) print("Dodat: \(item), Trenutni buffer: \(items)") condition.signal() // Signalizira čekajućim nitima } func removeItem() -> Int { condition.lock() defer { condition.unlock() } while items.isEmpty { condition.wait() // Čeka dok se ne pojavi element } let item = items.removeFirst() print("Uklonjen: \(item), Trenutni buffer: \(items)") condition.signal() // Signalizira čekajućim nitima return item } } -
Grand Central Dispatch (GCD):
-
Serial Queues: Izvršavaju zadatke redom, jedan po jedan na datom thread-u, što obezbeđuje atomarni pristup resursima.
-
Concurrent Queues sa Barrier Flags: Omogućava izvršavanje čitanja paralelno, ali operacije pisanja (write) se izvršavaju isključivo. Ovo implementira model read-write lock.
import Foundation class ThreadSafeArray<Element> { private var array: [Element] = [] private let queue = DispatchQueue(label: "com.mycompany.threadsafearray", attributes: .concurrent) // Konkurentna red func append(_ newElement: Element) { queue.async(flags: .barrier) { // Barrier za pisanje self.array.append(newElement) } } func get(at index: Int) -> Element? { var result: Element? queue.sync { // Sync za čitanje (ili async, ako redosled čitanja nije važan) if index < self.array.count { result = self.array[index] } } return result } }
-
-
Operacije Core Data Contexta: Svaki
NSManagedObjectContextima svoj sopstveni privatni serijalni thread. Pristup objektima i kontekstu treba vršiti samo sa tog thread-a.import CoreData // Primer čuvanja u Core Data kontekstu let context = // Dobijeni kontekst context.perform { // Izvršavanje na privatnom thread-u konteksta // Rad sa Core Data objektima do { try context.save() } catch { // Obrada greške } }
Izbor metode zavisi od konkretne zadatka i zahteva za performanse. GCD sa serijalnim ili paralelnim redovima sa barijerama je često najpreferiraniji pristup zbog svoje efikasnosti i jednostavnosti korišćenja. Za Core Data, uvek koristite metode perform ili performAndWait.