Sistemas Operativos

Sesión 8
Concurrencia, Sincronización
e Interbloqueo

Exclusión mutua · Semáforos · Condición de carrera · Deadlock

Última sesión teórica antes del cierre del primer corte. Aquí conectamos procesos, hilos y planificación con el problema real de "qué pasa cuando dos procesos quieren el mismo recurso al mismo tiempo".

Navegación: | F pantalla completa | Táctil: desliza

Plan de la sesión

120 minutos — última sesión teórica de la Unidad 1

  • 0–10 min — Puente: de planificación a "¿qué pasa si dos procesos compiten?"
  • 10–30 min — Multiprogramación: solicitudes, interrupciones y conmutación de contexto.
  • 30–55 min — Concurrencia: definición, condición de carrera, sección crítica.
  • 55–65 min — Pausa.
  • 65–90 min — Exclusión mutua: Mutex, Semáforo, lock. Monitores y paso de mensajes.
  • 90–110 min — Interbloqueo e inanición: condiciones de Coffman, detección y prevención.
  • 110–120 min — Cierre: conexión con el proyecto y la evaluación de la semana siguiente.

Indicadores trabajados hoy:

  • E - I: Multiprogramación, exclusión mutua, sincronización, interbloqueo e inanición, concurrencia y comunicación.
  • F - I: Interrupciones, excepciones, llamadas + todos los saberes de E-I.
  • G - I: Integración de procesos, hilos, planificación y concurrencia en el proyecto.
Puente con lo visto

De planificación a concurrencia: el paso natural

En las sesiones anteriores aprendimos que el scheduler decide qué proceso usa la CPU. Pero cuando el sistema es multiprogramado, varios procesos están en memoria al mismo tiempo y pueden querer acceder a los mismos recursos.

Lo que ya sabemos
  • Un proceso tiene estados: New, Ready, Running, Blocked, Terminated.
  • El scheduler elige quién pasa a Running.
  • FCFS, SJF y RR cambian el orden y los tiempos de espera.
  • La conmutación de contexto guarda y restaura el estado del proceso.
El problema nuevo
  • ¿Qué pasa si dos procesos leen y escriben el mismo dato "al mismo tiempo"?
  • ¿Puede el scheduler interrumpir un proceso en medio de una operación crítica?
  • ¿Qué ocurre si el Proceso A espera algo que tiene el Proceso B, y viceversa?

Idea central de hoy: la concurrencia no es un error del sistema, es una característica diseñada. El problema surge cuando no se coordina correctamente el acceso a recursos compartidos.

Multiprogramación

Varios procesos en memoria — solicitudes, interrupciones y conmutación

Multiprogramación

Técnica del SO para mantener múltiples procesos en memoria y cambiar la CPU entre ellos cuando uno se bloquea (espera I/O, señal, etc.). El objetivo es maximizar el uso de la CPU.

Solicitudes e interrupciones
  • Syscall: el proceso pide algo al SO voluntariamente (abrir archivo, leer red).
  • Interrupción hardware: el dispositivo avisa que terminó (señal asíncrona).
  • Excepción: error dentro del proceso (división por cero, acceso inválido).
Conmutación de contexto

Cuando el SO retira la CPU a un proceso (expropiación o bloqueo voluntario), guarda su contexto completo en el PCB (Program Counter, registros, estado de pila) y carga el contexto del siguiente proceso.

Este intercambio tiene un costo de tiempo (overhead). RR con quantum muy pequeño puede generar demasiadas conmutaciones y degradar el rendimiento.

Clave: la conmutación puede ocurrir en cualquier momento entre dos instrucciones. Eso hace posible la condición de carrera.

Concurrencia

Condición de carrera — cuando el orden importa y no está garantizado

Condición de carrera (Race Condition)

Ocurre cuando dos o más procesos/hilos acceden a un recurso compartido y el resultado depende del orden de ejecución, que el sistema no garantiza.

// Saldo inicial: 1000 // Proceso A lee saldo → 1000 // Proceso B lee saldo → 1000 // Proceso A resta 200 → escribe 800 // Proceso B resta 300 → escribe 700 // Resultado final: 700 (debería ser 500)
Sección crítica

Fragmento de código donde un proceso accede a recursos compartidos (variables, archivos, dispositivos). Solo un proceso a la vez debe ejecutar su sección crítica.

El problema de la sección crítica tiene tres requisitos de solución:

  • Exclusión mutua: solo uno dentro a la vez.
  • Progreso: si nadie está adentro, alguien debe poder entrar.
  • Espera acotada: ningún proceso espera indefinidamente.
Exclusión mutua

Mutex · Semáforo · Lock · Monitor · Paso de mensajes

Mutex

Objeto binario: bloqueado (1) o libre (0). El proceso que lo adquiere es el único que puede liberarlo. Ideal para proteger una sección crítica simple.

mutex.lock() // sección crítica mutex.unlock()
Semáforo

Contador entero ≥ 0. Operaciones atómicas wait() (decrementa) y signal() (incrementa). Permite controlar el acceso a N recursos simultáneos.

sem.wait() // P() // sección crítica sem.signal() // V()
Monitor / lock / paso de mensajes

Monitor: abstracción de alto nivel; el lenguaje garantiza exclusión dentro del monitor (C# lock, Java synchronized).

Paso de mensajes: los procesos no comparten memoria; se comunican enviando/recibiendo mensajes. Evita el problema de la sección crítica compartida por diseño.

Para el proyecto: elegir el mecanismo correcto depende del lenguaje y del tipo de recurso compartido. Lo importante es que sea atómico: que no pueda ser interrumpido a la mitad.

Interbloqueo (Deadlock)

Cuatro condiciones de Coffman — todas deben cumplirse simultáneamente

1. Exclusión mutua

Al menos un recurso no puede ser compartido simultáneamente.

2. Retención y espera

Un proceso retiene recursos mientras espera otros que otro proceso tiene.

3. Sin expropiación

El SO no puede quitarle un recurso a un proceso por la fuerza.

4. Espera circular

P1 espera un recurso de P2, P2 espera uno de P3, P3 espera uno de P1. Ciclo cerrado.

Estrategias frente al deadlock
  • Prevención: eliminar una de las 4 condiciones por diseño (ej. pedir todos los recursos de golpe → elimina retención y espera).
  • Evitación: algoritmo del Banquero — no asigna si pone al sistema en estado "inseguro".
  • Detección + recuperación: permitir que ocurra, detectar el ciclo y matar/reiniciar un proceso.
  • Ignorar: política "ostrich" — asumir que es tan raro que no vale el costo de manejarlo (Windows, Linux en algunos casos).
Inanición (Starvation)

Diferencia entre interbloqueo e inanición

AspectoInterbloqueoInanición
CausaEspera circular cerrada entre procesosUn proceso nunca recibe el recurso porque otros tienen prioridad
¿El proceso avanza?No — ninguno de los involucradosNo — solo el proceso "hambriento"
¿Hay ciclo?Sí, explícitoNo necesariamente
Ejemplo típicoP1 tiene A, quiere B; P2 tiene B, quiere ASJF con procesos largos que nunca corren porque siempre llega uno más corto
Solución habitualPrevención o detecciónAging: aumentar la prioridad del proceso que lleva mucho esperando

Recuerda de la sesión 6: SJF puro puede causar inanición en procesos largos. RR con quantum adecuado evita inanición porque garantiza que todos corren eventualmente.

Para la tarea evaluativa de Unidad 1 - Actividad 3 - Tarea 1 ("Analizando la administración de procesos en multitarea"), ya resolvieron Gantt y métricas. Esta sesión les da el vocabulario para justificar también si un algoritmo puede causar inanición.

Ejemplo integrador

Banco con dos cajeros — del problema a la solución

Sin sincronización — condición de carrera
Hilo A: lee saldo = 1000 Hilo B: lee saldo = 1000 Hilo A: saldo = 1000 - 200 → escribe 800 Hilo B: saldo = 1000 - 300 → escribe 700 // Saldo final: 700 (perdimos 200)
Con Mutex — correcto
Hilo A: adquiere mutex lee saldo = 1000 saldo = 800 → escribe libera mutex Hilo B: adquiere mutex lee saldo = 800 saldo = 500 → escribe libera mutex // Saldo final: 500 ✓
¿Qué cambió?
  • La sección crítica (leer-modificar-escribir) es atómica: nadie puede interrumpirla.
  • El mutex garantiza que solo un hilo está en esa sección a la vez.
  • El orden exacto puede variar, pero el resultado siempre es correcto.

Conexión con el proyecto: si tu proyecto tiene hilos que comparten una variable, un archivo o una cola, necesitas exactamente este patrón. Identificar la sección crítica es el primer paso antes de escribir una sola línea de código concurrente.

Patrón clásico

Productor–Consumidor con semáforos

El escenario

Un proceso produce datos y los pone en un buffer compartido. Otro proceso consume esos datos. El buffer tiene capacidad limitada (N posiciones).

  • El productor no puede agregar si el buffer está lleno.
  • El consumidor no puede tomar si el buffer está vacío.
  • Ambos no pueden acceder al buffer al mismo tiempo.
Tres semáforos necesarios
  • mutex (inicia en 1): exclusión mutua al acceder al buffer.
  • lleno (inicia en 0): cuenta posiciones ocupadas.
  • vacío (inicia en N): cuenta posiciones libres.
// PRODUCTOR loop: produce(item) vacío.wait() // espera si buffer lleno mutex.wait() buffer.add(item) mutex.signal() lleno.signal() // avisa que hay un item // CONSUMIDOR loop: lleno.wait() // espera si buffer vacío mutex.wait() item = buffer.remove() mutex.signal() vacío.signal() // avisa que hay espacio consume(item)

Este patrón aparece en tu proyecto si tienes un hilo generando datos y otro procesándolos: logs concurrentes, tareas en cola, sensor + procesador, etc.

Cierre de la Unidad 1

Todo lo que cubre la Unidad 1 — qué ya saben y qué conecta con qué

Bloque de saberSesionesEstado
Perspectiva histórica, definición y estructura del SO. Tipos y funciones.S1 – S3Cubierto
Arquitecturas hardware (Von Neumann / Harvard). Interrupciones, excepciones y llamadas al sistema.S3 – S4Cubierto
Definición, control y estados de un proceso. Hilos. PCB.S4 – S5Cubierto
Planificación de procesos y algoritmos (FCFS, SJF, RR). Métricas.S5 – S6Cubierto
Proyecto — Primera entrega (propuesta + mock + Incremento 1).S7Cubierto
Multiprogramación, concurrencia, exclusión mutua, sincronización, interbloqueo e inanición.S8 (hoy)En curso

La Unidad 1 queda completa con esta sesión. Las dos próximas sesiones son evaluativas: Proyecto E1 (ya entregada) y "Reconociendo lo aprendido Unidad 1" (05/03/2026, individual, 10%).

Actividad evaluativa — semana de cierre

Reconociendo lo aprendido — Unidad 1 (individual · 10% · 05/03/2026)

Parte 1 — Conceptos clave
  • Programa vs. proceso.
  • Estados de proceso y transiciones.
  • Recursos: CPU, memoria, I/O.
  • Multitarea, multiprogramación.
  • Sección crítica, exclusión mutua, condición de carrera.
  • Interbloqueo e inanición: diferencia y solución básica.
Parte 2 — Mini ejercicio de planificación

Aplicar FIFO o Round Robin a un conjunto pequeño de procesos, construir el Gantt, calcular T, W, R y justificar el resultado.

Parte 3 — Reflexión (8–12 líneas): explicar por qué los mecanismos de gestión de procesos y la planificación impactan el rendimiento y la experiencia del usuario. Se valora argumentación, no solo definiciones.

Cómo prepararse:

  • Revisar las sesiones 1 a 8 (especialmente S5, S6 y S8).
  • Practicar Gantt con los ejercicios de la S6.
  • Para la reflexión: conectar "planificación mala = espera larga = usuario frustrado".
Conexión con el proyecto

Lo de hoy va directo al Incremento 2 y a la Entrega Final

Lo que deben identificar en su proyecto ahora
  1. ¿Hay recursos compartidos entre hilos o procesos? ¿Cuáles?
  2. ¿Cuál es la sección crítica exacta en su código?
  3. ¿Qué mecanismo usarán: Mutex, Semáforo, lock o paso de mensajes?
  4. ¿Puede ocurrir un deadlock en su diseño? ¿Por cuál de las 4 condiciones?
  5. ¿Cómo lo demostrarán (y solucionarán) en la Entrega Final?

Recuerden: la sustentación (25% de la nota final del proyecto) incluye preguntas sobre:

  • ¿Dónde está la sección crítica en su código?
  • ¿Por qué eligieron ese mecanismo de sincronización?
  • ¿Pueden mostrar la condición de carrera que resolvieron?

Buena práctica: documentar en el README del repositorio cuál es la sección crítica y qué mecanismo se usa. Un commit con ese cambio es evidencia de que lo pensaron, no lo hicieron al final.