Threads son unidades de ejecución dentro de un proceso que comparten el mismo espacio de direcciones. La concurrency permite múltiples threads progresando simultáneamente, pero introduce problemas de sincronización.
Threads vs Procesos
| Aspecto | Proceso | Thread |
|---|---|---|
| Espacio de direcciones | Privado | Compartido |
| Creación | Lenta | Rápida |
| Comunicación | IPC | Memoria compartida |
| Bloqueo | Todo el proceso | Solo el thread |
Concurrency vs Parallelism
- Concurrency: múltiples tareas progresando en el mismo CPU (interleaved).
- Parallelism: múltiples tareas ejecutándose en CPUs distintos simultáneamente.
Race Condition
Ocurre cuando múltiples threads acceden a datos compartidos concurrentemente y el resultado depende del orden de ejecución.
Ejemplo:
counter = 0
thread 1: counter++ (read 0, increment 1, write 1)
thread 2: counter++ (read 0, increment 1, write 1)
Resultado esperado: 2
Resultado real: 1
Critical Section
Sección de código que accede a recurso compartido. Debe ejecutarse de forma mutuamente exclusiva: solo un thread a la vez.
Sincronización
Mutex (Mutual Exclusion)
Garantiza que solo un thread esté en la critical section a la vez.
lock(mutex)
// critical section
unlock(mutex)
Semáforos
- Binary semaphore: 0 o 1 (equivalente a mutex).
- Counting semaphore: contador para múltiples recursos.
wait(sem) // decrementa, bloquea si 0
signal(sem) // incrementa, desbloquea uno
Condition Variables
Permiten threads esperar hasta que una condición se cumpla.
wait(cv, mutex) // libera mutex, espera señal
signal(cv) // despierta un thread esperando
Problemas Clásicos
| Problema | Descripción |
|---|---|
| Productor-Consumidor | Buffer limitado, producir y consumir |
| Lectores-Escritores | Múltiples lectores o un escritor |
| Filósofos Cenadores | 5 filósofos, 5 tenedores |
Aplicaciones
- Servidores web — pool de threads para conexiones
- Databases — concurrencia en transacciones
- Sistemas de tiempo real — scheduling determinista
- Enseñanza — introduce sincronización y race conditions
Trayectoria de Práctica
- Escribe un programa con race condition; ejecútalo muchas veces hasta ver el bug.
- Corrige con mutex; verifica que desaparece.
- Implementa productor-consumidor con semáforos.
- Investiga lock-free programming: ¿cómo evita locks?
- Investiga transactional memory: ¿es el futuro de concurrency?