Sobes.tech
Middle

Mis on võistluse seisund (race condition)?

sobes.tech AI

Vastus AI-lt

Riski olukord tekib, kui kaks või enam niiti või protsessi samaaegselt pääsevad ühisele ressursile (näiteks muutujale, failile, andmebaasile) ning operatsiooni tulemus sõltub sellest, millises järjekorras need niidid/protsessid oma tegevused sooritavad. Andmete juurdepääsu ja muutmise ettearvamatu järjekorra tõttu võib tulemus olla ebatäpne või ootamatu:

Näide iOS-is: Oletame, et meil on loendur count, millele pääsevad samaaegselt ligi kaks niiti, et seda suurendada:

var count = 0

func incrementCount() {
    // Niit 1 loeb count = 5
    // Niit 2 loeb count = 5
    let currentCount = count
    // Niit 1 arvutab newCount = 6
    // Niit 2 arvutab newCount = 6
    let newCount = currentCount + 1
    // Niit 1 kirjutab count = 6
    // Niit 2 kirjutab count = 6 (ülekirjutades Niit 1 tulemuse)
    count = newCount
}

// Kui kaks niiti kutsuvad samaaegselt välja incrementCount(),
// oodatav tulemus oleks count = 2,
// kuid riskiseisundi tõttu võib count olla 1.

Riskiseisundi vältimiseks kasutatakse sünkroniseerimismehhanisme:

  • Lock/Mutex: Blokeerib juurdepääsu ressursile, kuni niit seda kasutab:
    import Foundation
    
    let lock = NSLock()
    var count = 0
    
    func incrementCount() {
        lock.lock() // Lukustuse haaramine
        let currentCount = count
        let newCount = currentCount + 1
        count = newCount
        lock.unlock() // Lukust vabastamine
    }
    
  • Järjekorrad (Queues): Kasutades järjestikuseid GCD-queue:
    import Foundation
    
    let serialQueue = DispatchQueue(label: "com.myapp.counterQueue")
    var count = 0
    
    func incrementCount() {
        serialQueue.async {
            let currentCount = count
            let newCount = currentCount + 1
            count = newCount
        }
    }
    
  • Atomaarsed operatsioonid: Puhas operatsioon protsessori juhiste tasemel. Swiftis saab kasutada OSAtomic... (vana) või Atomic @_implementationOnly import Atomics kaudu (eksperimentaalne), või lähenemisi, mis põhinevad lukustustel/järjekordadel:

Sünkroniseerimise meetodi valik sõltub konkreetsest stsenaariumist ja jõudlusnõuetest. Oluline on mõista, et sünkroniseerimine võib lisada täiendavat koormust ning potentsiaalselt viia vastastikusesse lukustamisse (deadlock), kui seda valesti rakendada.