Sobes.tech
Middle+

Hogyan szinkronizáljuk az adatok közötti adatokat a szálak között, és hogyan biztosítjuk a kontextus összhangját?

sobes.tech MI

Válasz az MI-től

Az adatok szinkronizálásához és a kontextus összhangjának biztosításához több szálon futó alkalmazásban az alábbi megközelítéseket használják:

  1. NSLock / Lock: Egyszerű mutexek a kritikus kód szekciók zárolására.

    import Foundation
    
    class ThreadSafeCounter {
        private var count: Int = 0
        private let lock = NSLock()
    
        func increment() {
            lock.lock()
            defer { lock.unlock() } // A zárolás feloldásának garantálása
            count += 1
        }
    
        func getCount() -> Int {
            lock.lock()
            defer { lock.unlock() }
            return count
        }
    }
    
  2. NSRecursiveLock: Lehetővé teszi a zárolás többszöri újrafogását ugyanazon a szálon.

    import Foundation
    
    class RecursiveLocker {
        private let lock = NSRecursiveLock()
    
        func firstMethod() {
            lock.lock()
            defer { lock.unlock() }
            print("Első módszer")
            secondMethod() // Ismételt zárolás lehetséges
        }
    
        func secondMethod() {
            lock.lock()
            defer { lock.unlock() }
            print("Második módszer")
        }
    }
    
  3. NSCondition / NSConditionLock: Lehetővé teszi a szálaknak, hogy bizonyos feltétel (Condition) vagy érték (ConditionLock) teljesüléséig várjanak, mielőtt folytatnák a végrehajtást. Producer-consumer minták megvalósítására használják.

    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() // Vár, amíg hely nem lesz
            }
    
            items.append(item)
            print("Hozzáadva: \(item), Aktuális buffer: \(items)")
            condition.signal() // Jelzi a várakozó szálaknak
        }
    
        func removeItem() -> Int {
            condition.lock()
            defer { condition.unlock() }
    
            while items.isEmpty {
                condition.wait() // Vár, amíg elem nem jelenik meg
            }
    
            let item = items.removeFirst()
            print("Eltávolítva: \(item), Aktuális buffer: \(items)")
            condition.signal() // Jelzi a várakozó szálaknak
            return item
        }
    }
    
  4. Grand Central Dispatch (GCD):

    • Serial Queues: Feladatokat egymás után hajt végre, egyenként egy adott szálon, biztosítva az erőforrások atomikus hozzáférését.

    • Concurrent Queues Barrier Flags-szel: Lehetővé teszi az olvasás párhuzamos végrehajtását, de az írási műveletek (write) kizárólagosan futnak. Ez a read-write lock modellt valósítja meg.

      import Foundation
      
      class ThreadSafeArray<Element> {
          private var array: [Element] = []
          private let queue =
          DispatchQueue(label: "com.mycompany.threadsafearray", attributes: .concurrent) // Párhuzamos sor
      
          func append(_ newElement: Element) {
              queue.async(flags: .barrier) { // Barrier íráshoz
                  self.array.append(newElement)
              }
          }
      
          func get(at index: Int) -> Element? {
              var result: Element?
              queue.sync { // Szinkron olvasás (vagy async, ha nem számít a sorrend)
                  if index < self.array.count {
                      result = self.array[index]
                  }
              }
              return result
          }
      }
      
  5. Core Data Context műveletek: Minden NSManagedObjectContext saját, privát soros szálával rendelkezik. Az objektumokhoz és a kontextushoz való hozzáférést csak ebből a szálból szabad végezni.

    import CoreData
    
    // Példa a Core Data kontextus mentésére
    let context = // A kapott kontextus
    context.perform { // A kontextus saját szálán végrehajtva
        // Core Data objektumokkal való munka
        do {
            try context.save()
        } catch {
            // Hibakezelés
        }
    }
    

A módszer kiválasztása a konkrét feladattól és a teljesítménykövetelményektől függ. A GCD soros vagy párhuzamos sorokat barrier-ekkel gyakran a leghatékonyabb és legegyszerűbb megközelítés, mivel hatékony és könnyen használható. A Core Data esetében mindig a perform vagy performAndWait módszereket használja.