Sobes.tech
Middle

¿Qué es una condición de carrera (race condition)?

sobes.tech AI

Respuesta de la IA

La condición de carrera ocurre cuando dos o más hilos o procesos acceden simultáneamente a un recurso compartido (por ejemplo, una variable, un archivo, una base de datos) y el resultado de la operación depende del orden en que estos hilos/procesos realizan sus acciones. Debido al orden impredecible de acceso y modificación de datos, el resultado puede ser incorrecto o inesperado.

Ejemplo en iOS: Supongamos que tenemos un contador count, al que acceden simultáneamente dos hilos para incrementarlo.

var count = 0

func incrementCount() {
    // Hilo 1 lee count = 5
    // Hilo 2 lee count = 5
    let currentCount = count
    // Hilo 1 calcula newCount = 6
    // Hilo 2 calcula newCount = 6
    let newCount = currentCount + 1
    // Hilo 1 escribe count = 6
    // Hilo 2 escribe count = 6 (sobreescribiendo el resultado del Hilo 1)
    count = newCount
}

// Si dos hilos llaman a incrementCount() simultáneamente,
// el resultado esperado sería count = 2,
// pero debido a la condición de carrera, count puede ser 1.

Para prevenir condiciones de carrera, se utilizan mecanismos de sincronización:

  • Lock/Muerto: Bloquean el acceso al recurso mientras el hilo lo usa.
    import Foundation
    
    let lock = NSLock()
    var count = 0
    
    func incrementCount() {
        lock.lock() // Adquiere el bloqueo
        let currentCount = count
        let newCount = currentCount + 1
        count = newCount
        lock.unlock() // Libera el bloqueo
    }
    
  • Colas (Queues): Uso de colas secuenciales GCD.
    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
        }
    }
    
  • Operaciones atómicas: Operaciones indivisibles a nivel de instrucciones del procesador. En Swift, se puede usar OSAtomic... (obsoleto) o Atomic de @_implementationOnly import Atomics (experimental), o enfoques basados en bloqueos/colas.

La elección del método de sincronización depende del escenario específico y los requisitos de rendimiento. Es importante entender que la sincronización puede introducir carga adicional y potencialmente causar bloqueos mutuos (deadlocks) si no se implementa correctamente.