Cos'è una condizione di gara (race condition)?
sobes.tech AI
Risposta dell'AI
La condizione di race si verifica quando due o più thread o processi accedono contemporaneamente a una risorsa condivisa (ad esempio, una variabile, un file, un database) e il risultato dell'operazione dipende dall'ordine in cui questi thread/processi eseguono le loro azioni. A causa dell'ordine imprevedibile di accesso e modifica dei dati, il risultato può essere errato o inaspettato.
Esempio in iOS:
Supponiamo di avere un contatore count, a cui accedono contemporaneamente due thread per incrementarlo.
var count = 0
func incrementCount() {
// Il Thread 1 legge count = 5
// Il Thread 2 legge count = 5
let currentCount = count
// Il Thread 1 calcola newCount = 6
// Il Thread 2 calcola newCount = 6
let newCount = currentCount + 1
// Il Thread 1 scrive count = 6
// Il Thread 2 scrive count = 6 (sovrascrivendo il risultato del Thread 1)
count = newCount
}
// Se due thread chiamano incrementCount() contemporaneamente,
// il risultato atteso sarebbe count = 2,
// ma a causa della condizione di race, count può diventare 1.
Per prevenire le condizioni di race, si utilizzano meccanismi di sincronizzazione:
- Lock/Muoro: Blocca l'accesso alla risorsa mentre il thread la utilizza.
import Foundation let lock = NSLock() var count = 0 func incrementCount() { lock.lock() // Acquisisce il lock let currentCount = count let newCount = currentCount + 1 count = newCount lock.unlock() // Rilascia il lock } - Code (Queue): Uso di code GCD sequenziali.
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 } } - Operazioni atomiche: Operazioni indivisibili a livello di istruzioni del processore. In Swift, si può usare
OSAtomic...(obsoleto) oAtomicda@_implementationOnly import Atomics(sperimentale), o approcci basati su lock/queue.
La scelta del metodo di sincronizzazione dipende dallo scenario specifico e dai requisiti di prestazioni. È importante capire che la sincronizzazione può introdurre carico aggiuntivo e potenzialmente portare a deadlock se non implementata correttamente.