🐧 FSO — Repaso de última hora
Viernes 3 jul · 15:00 · Edif. ARQUITECTURA, labs D08 (LQ-2), E05 (LQ-D), E06 (LQ-C) · llega 14:45
⚠️ REGLA DE ORO: JUSTIFICA TODAS las respuestas de los ejercicios. Un resultado sin justificar = NULO. En el test no arriesgues a lo loco.
🎯 Para aprobar: teoría ≥6/10 (tu PAC es 0, no hay colchón) y práctico ≥2/3. Nota final = 0,75 × (TEO + PRA). Son pruebas separadas la misma tarde: preséntate a las dos.
⏱️ PLANIFICACIÓN (cae seguro)
TR (retorno) = TF − llegada
TE (espera) = TR − ráfaga
TE también = instante en que EMPIEZA − llegada (si no lo interrumpen) ← comprobación
Reglas de cada algoritmo:
- FCFS: estricto orden de LLEGADA.
- SJF: cuando la CPU se libera → el más CORTO de los que YA están esperando (¡NO el que llegó antes! — tu fallo del drill).
- SRTF: SJF expulsivo — si llega uno con MENOS tiempo restante que el actual, lo desaloja.
- RR: turnos de quantum Q; el que no acaba vuelve al FINAL de la cola. Q grande→FCFS, Q pequeño→muchos cambios de contexto.
- Prioridades: riesgo de inanición → se arregla con envejecimiento (aging).
RR numérico (examen 2019): N procesos, ráfaga B, Q=1, todos llegan en 0:
Retorno del 1º = (B−1)·N + 1
Vaciado de la cola = N·B
Cambios de contexto ≈ N·B
Espera media = (B−1)·N + (N+1)/2 − B
Ej. real: N=20, B=2 → 21 ms · 40 ms · ~40 · 28,5 ms
🧠 MEMORIA (cae seguro)
bits de offset = log₂(tamaño de página)
nº páginas lógicas = 2^(bits lógicos − offset)
nº marcos físicos = 2^(bits físicos − offset)
página = dirección ÷ tamaño (división entera)
offset = dirección mod tamaño
FÍSICA = marco × tamaño + offset (el offset NO cambia)
Ejemplo real 2019: lógicas 48 bits, físicas 32, página 64 KiB (=2¹⁶) → offset 16 bits → 2³² páginas y 2¹⁶ = 65 536 marcos.
TLB (tiempo efectivo):
T = h·T_RAM + (1−h)·(niveles+1)·T_RAM
Ej. 2019: 0,95·50 + 0,05·(3·50) = 55 ns (2 niveles → ×3 en el fallo)
Reemplazo de páginas (haz la tabla columna a columna):
- FIFO: expulsa la que ENTRÓ primero (ignora el uso).
- LRU: expulsa la que hace MÁS que no se USA.
- ÓPTIMO: la que más tardará en volver a usarse (teórico, para comparar).
Preguntas cortas que se repiten:
- Bit de validez: 1=página en RAM; 0=no está → acceso dispara FALLO DE PÁGINA y el SO la trae del disco.
- Bit de referencia: marca si la página se ha usado recientemente; lo usan reloj/NRU para aproximar LRU. Sin él → reemplazos a ciegas, peores expulsiones.
- ¿RAM = disco? ¿sirve la MV? Sí: sigue dando espacio lógico grande por proceso, protección/aislamiento y compartición — no solo "más memoria".
- Thrashing (hiperpaginación): demasiados procesos sin marcos suficientes → todo el tiempo en fallos de página, CPU ociosa, disco a tope. Solución: bajar multiprogramación o más RAM.
⚡ CONCURRENCIA (cae seguro)
Sección crítica — 3 propiedades (para "analiza este algoritmo"):
- Exclusión mutua: nunca dos dentro.
- Progreso: si nadie está dentro, no se bloquea a quien quiere entrar.
- Espera limitada: no te pueden adelantar infinitas veces.
Método: busca UN entrelazado que rompa una propiedad → incorrecto.
Peterson correcto: flag[i]=true; turn=j; while(flag[j] && turn==j); — si falta el
turn=j ANTES del while, FALLA la exclusión mutua (cayó en 2019).
EL problema estrella (depósito/surtidor/impresora — 100% de extraordinarias):
float cantidad = 0;
pthread_mutex_t m; pthread_cond_t cv;
void sacar(float L) {
pthread_mutex_lock(&m);
while (cantidad < L) // WHILE, nunca if
pthread_cond_wait(&cv, &m); // duerme y SUELTA el mutex
cantidad -= L;
pthread_mutex_unlock(&m);
}
void poner(float L) {
pthread_mutex_lock(&m);
cantidad += L;
pthread_cond_broadcast(&cv); // despierta a TODOS
pthread_mutex_unlock(&m);
}
Por qué:
while (re-comprobar al despertar) ·
wait suelta el mutex mientras duerme ·
broadcast porque esperan cantidades distintas.
Semáforos — productor/consumidor: mutex=1, vacios=N, llenos=0.
Productor: wait(vacios) → wait(mutex) → meter → signal(mutex) → signal(llenos)
Consumidor: wait(llenos) → wait(mutex) → sacar → signal(mutex) → signal(vacios)
Interbloqueo (Coffman, las 4 a la vez): exclusión mutua · retención y espera · sin expropiación · espera circular. Romper UNA lo previene.
🛠️ PRÁCTICO (50 min, PC Linux, ≥2/3)
lanza_hijos.c (cayó tal cual en el parcial):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char *argv[]) {
int n = atoi(argv[1]);
for (int i = 0; i < n; i++) {
pid_t pid = fork();
if (pid == 0) { // HIJO
printf("Hijo %d: PID %d\n", i, getpid());
exit(0); // ¡SIN ESTO, BOMBA DE PROCESOS!
}
}
for (int i = 0; i < n; i++) wait(NULL);
return 0;
}
fork() → 0 al hijo, PID del hijo al padre, −1 error. Padre e hijo
NO comparten variables (copias). Los
hilos SÍ comparten.
copiar fichero:
int fo = open("orig.txt", O_RDONLY);
int fd = open("dest.txt", O_WRONLY|O_CREAT|O_TRUNC, 0644);
char buf[512]; ssize_t n;
while ((n = read(fo, buf, sizeof(buf))) > 0)
write(fd, buf, n); // n, ¡NO sizeof(buf)!
close(fo); close(fd);
read devuelve 0 al final del fichero, −1 error. Cabeceras:
fcntl.h (open) y
unistd.h (read/write/close).
hilos: pthread_create(&h,NULL,func,&arg) · pthread_join(h,NULL) · mutex lock/unlock alrededor de lo compartido. Compilar: gcc p.c -o p -pthread
CLI rápido: gcc p.c -o p → ./p · man 2 fork · ls -l · cat f · cp a b · mv a b · rm -r d · mkdir d · grep "x" f · ps aux | grep p · kill -9 PID · chmod +x f · redirección > añade >> · tubería |
📄 TEST — hechos que caen (del test real)
- RAM infinita → sobraría la memoria virtual (protección y caché de disco seguirían haciendo falta).
- Nóminas mensuales sin interacción → procesamiento por lotes.
- "Independencia del dispositivo" = interfaz UNIFORME de E/S.
read() es llamada al sistema; fprintf() es de biblioteca.
- Imposible: tiempo compartido NO multitarea (contradicción).
- Instrucción ilegal → 1º se conmuta a modo núcleo, luego rutina, luego abortar.
- Apps ejecutan código del núcleo solo de forma controlada (syscalls).
- Módulos cargables = núcleo monolítico con carga dinámica (Linux).
- El SO actúa en respuesta a eventos.
- Kernel = parte residente en memoria que atiende syscalls/eventos. Micronúcleo = kernel mínimo + servicios como procesos.
- Estados: LISTO (quiere CPU) ↔ EJECUCIÓN ↔ BLOQUEADO (espera E/S; NO compite por CPU).
- Ensayo (75-150 palabras): seguridad=permisos/usuarios · rendimiento=caché de disco/multiprogramación · usabilidad=GUI/shell.
🧘 Antes de entrar: respira. Empieza por lo que domines (planificación y memoria son mecánicos). Gantt SIEMPRE en papel. Verifica esperas con el doble método. Si un resultado te parece imposible (espera mayor que todo lo que hay delante), repásalo. ¡Y justifica TODO! Suerte 🍀