0Pricing
Swift Academy · Lección

El problema de las condiciones de carrera

Comprenda por qué la mutación concurrente no es segura.

El problema de las condiciones de carrera es una lección gratuita de Swift Academy en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Swift Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Swift Academy incluye 4 lecciones en total.

¿Qué es una condición de carrera de datos?

Una condición de carrera de datos ocurre cuando dos o más hilos acceden simultáneamente a la misma ubicación de memoria, al menos uno de los accesos es una escritura y no existe sincronización entre ellos.

El resultado es un comportamiento indefinido: valores corruptos, cierres inesperados o errores que solo aparecen bajo carga.

Estado mutable compartido

La causa fundamental de las condiciones de carrera de datos es el estado mutable compartido. Si muchas tareas pueden leer y escribir la misma variable, el orden se vuelve impredecible.

El contador siguiente puede perder incrementos porque count += 1 es una operación de lectura-modificación-escritura, no atómica.

final class Counter {
    var count = 0
    func increment() {
        count += 1 // read, add, write: not atomic
    }
}

Por qué se pierden los incrementos

La instrucción count += 1 se compila en tres pasos: cargar el valor, sumarle uno y volver a almacenarlo.

Si dos hilos cargan 5 al mismo tiempo, ambos almacenan 6 y uno de los incrementos desaparece.

// Thread A loads 5
// Thread B loads 5
// Thread A stores 6
// Thread B stores 6  <-- lost update

Desgarro de valores grandes

Además de perder actualizaciones, las escrituras simultáneas de valores de varias palabras, como una estructura o un valor de 64 bits en algunas plataformas, pueden sufrir un desgarro: un lector ve la mitad de una escritura y la mitad de otra.

struct Point { var x: Double; var y: Double }
var p = Point(x: 0, y: 0)
// Concurrent writes may leave x from one write and y from another

La solución anterior: los bloqueos

Antes de Swift Concurrency, la solución clásica era un bloqueo (mutex). Solo un hilo puede mantener el bloqueo a la vez, lo que serializa el acceso.

Los bloqueos funcionan, pero es fácil usarlos incorrectamente: olvidar desbloquear, provocar interbloqueos o causar inversión de prioridades.

import Foundation
final class SafeCounter {
    private let lock = NSLock()
    private var count = 0
    func increment() {
        lock.lock()
        defer { lock.unlock() }
        count += 1
    }
}

Colas de despacho seriales

Otro enfoque clásico es una cola de despacho serial. Todas las mutaciones se canalizan a una única cola, por lo que nunca se solapan.

import Foundation
final class QueueCounter {
    private let queue = DispatchQueue(label: "counter")
    private var count = 0
    func increment() {
        queue.async { self.count += 1 }
    }
}

Por qué la sincronización manual es frágil

Los bloqueos y las colas dependen de la disciplina. El compilador no comprueba que cada acceso esté protegido.

Basta con que se cuele una lectura sin protección para que vuelva a producirse la condición de carrera. No existe ninguna garantía en tiempo de compilación.

// Nothing stops a careless reader from doing this:
// let value = counter.count  // unsynchronized read = race

Swift Concurrency cambia las reglas

Swift Concurrency convierte la seguridad frente a las condiciones de carrera de datos en una funcionalidad del lenguaje en lugar de una convención.

Tres herramientas colaboran: actor para proteger el estado mutable, Sendable para los tipos que se pueden compartir de forma segura y el compilador para hacer cumplir ambas garantías.

actor Counter {
    private var count = 0
    func increment() { count += 1 }
}

Los actores serializan el acceso

Un actor garantiza que solo una tarea ejecute su código que modifica el estado cada vez. El entorno de ejecución serializa el acceso automáticamente.

No tiene que escribir ningún bloqueo; el modelo de actores proporciona la sincronización.

actor BankAccount {
    private(set) var balance = 0
    func deposit(_ amount: Int) { balance += amount }
}

Cumplimiento en tiempo de compilación

El compilador no permite acceder al estado aislado por un actor sin pasar por el actor. Las llamadas entre actores se vuelven asíncronas (await).

Esto convierte las condiciones de carrera en errores en tiempo de compilación.

let account = BankAccount()
// Must await: balance is actor-isolated
// let b = await account.balance

Sendable delimita lo que atraviesa los hilos

El protocolo Sendable identifica los tipos que se pueden pasar de forma segura a través de los límites de concurrencia.

El compilador impide enviar estado mutable que no sea Sendable a otra tarea, evitando la condición de carrera desde el nivel de tipos.

struct Money: Sendable {
    let amount: Int
    let currency: String
}

Comprobación rápida: condiciones de carrera de datos

Compruebe su comprensión de las causas de una condición de carrera de datos.

Repaso: el problema de las condiciones de carrera de datos

Las condiciones de carrera de datos se deben al estado mutable compartido al que se accede simultáneamente sin sincronización, lo que produce actualizaciones perdidas, desgarros y comportamiento indefinido.

Las soluciones antiguas, como los bloqueos y las colas seriales, funcionan, pero no se comprueban y son frágiles. Swift Concurrency reemplaza la convención por cumplimiento: actor aísla el estado, Sendable delimita lo que atraviesa los límites y el compilador verifica la seguridad. El resto del curso explora estas herramientas en profundidad.

Preguntas frecuentes

¿La lección «El problema de las condiciones de carrera» es gratis?

Sí — el texto completo de «El problema de las condiciones de carrera» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Swift Academy, actualiza a CoddyKit PRO. El curso de Swift Academy incluye 4 lecciones en total.

¿Qué aprenderé en «El problema de las condiciones de carrera»?

Comprenda por qué la mutación concurrente no es segura. Practicas Swift Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Swift Academy?

No se requiere experiencia previa. Swift Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.

¿Cuánto tiempo toma la lección «El problema de las condiciones de carrera»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Swift Academy?

Sí. Cada lección de Swift Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. El problema de las condiciones de carrera
  2. El protocolo Sendable
  3. Aislamiento de actores y nonisolated
  4. Migración a la concurrencia estricta
← Volver a Swift Academy