1. De la solicitud más cercana al barrido direccional
En el tema 42, SSTF elegía la solicitud más cercana desde cada nueva posición. Esa elección podía cambiar repetidamente de sentido o postergar una petición lejana ante nuevas llegadas cercanas. Ahora agregaremos un estado: la dirección de servicio.
Barrido direccional: atender las solicitudes disponibles en un sentido, según su posición, y aplicar una regla explícita al terminar ese tramo. SCAN, C-SCAN y LOOK se diferencian por dónde termina el barrido y cómo comienza el siguiente.
La analogía del ascensor ayuda: si está subiendo, atiende destinos superiores en orden, sin regresar por un piso inferior solo porque esté cerca. En el disco, «subir» significa ir hacia números de cilindro mayores, no una orientación física universal.
2. Dirección, límites y criterio de finalización
Antes de calcular fijamos las convenciones. Algunos ejercicios omiten el retorno circular o completan un barrido después del último servicio; eso responde otra pregunta y produce otros totales.
- El disco del ejemplo tiene cilindros de 0 a M=199: son 200 posiciones, y la distancia entre extremos es 199.
- El cabezal comienza en 53. La dirección inicial se proporciona como ascendente o descendente.
- Todas las solicitudes están disponibles al inicio; su índice conserva la identidad y desempata cilindros iguales.
- Se atienden primero las solicitudes en la posición actual, sin desplazamiento.
- El movimiento no es apropiativo: se completa el evento seleccionado.
- SCAN y C-SCAN alcanzan el extremo del sentido actual cuando quedan peticiones al otro lado.
- El retorno de C-SCAN entre extremos cuenta completo y no atiende solicitudes durante el viaje.
- La simulación termina al completar la última solicitud. No agrega desplazamientos cuando ya no queda trabajo.
La regla final delimita una observación finita de la cola: si todas las solicitudes están por delante, las tres políticas se detienen en la última atendida. No estamos simulando un cabezal que sigue recorriendo un disco sin trabajo.
Las coordenadas son didácticas. No convertimos direcciones LBA en cilindros físicos ni atribuimos este comportamiento a un SSD o a un planificador concreto de Linux.
3. Atender una petición y mover el cabezal
La traza distinguirá tres tipos de evento. Así podemos revisar qué parte del recorrido atiende trabajo y qué parte prepara un nuevo barrido.
| Tipo | Identificador | Significado |
|---|---|---|
| peticion | R1, R2, etc. | Viajar hasta esa solicitud y atenderla; puede tener distancia cero. |
| extremo | 0 en la salida C. | Completar el trayecto hasta 0 o M sin atender una nueva solicitud. |
| salto | 0 en la salida C. | Retorno físico de C-SCAN de un extremo al opuesto, sin servicio durante el viaje. |
distancia_evento = |destino − origen|
D = suma de distancias de TODOS los eventos
J = suma de distancias de los eventos salto
recorrido medio por petición = D / cantidad_de_peticiones
Los eventos extremo y salto no aumentan la cantidad de peticiones.«Salto» es una etiqueta de la traza, no una teletransportación. Aunque C-SCAN concibe el servicio de forma circular, el cabezal debe desplazarse físicamente. El subtotal D−J se puede mostrar para auditar el cálculo, pero no es el recorrido total físico.
Omitimos eventos extremo de distancia cero: si ya estamos allí, no hay otro viaje. Una petición real situada en ese extremo se conserva y puede aparecer antes del retorno.
4. SCAN: llegar al extremo y cambiar de sentido
SCAN atiende las peticiones en el sentido actual por orden de cilindro. Cuando ya no queda ninguna en ese sentido, pero sí al otro lado, continúa hasta el extremo y cambia de dirección. En el regreso vuelve a atender peticiones.
mientras queden solicitudes:
si hay una en la posición actual o por delante:
atender la más próxima en el sentido de avance
si no:
mover al extremo de ese sentido, si aún no estamos allí
invertir la direcciónCon dirección ascendente, primero se atienden coordenadas mayores en orden creciente; al volver, las menores se atienden en orden decreciente. Una petición detrás del cabezal no provoca una inversión inmediata si todavía hay trabajo delante.
Para mantener la distinción con LOOK, el giro de SCAN se hace en el extremo del disco definido por el modelo. Si invertimos en la última petición del sentido actual, ya estamos aplicando LOOK.
5. Traza completa de SCAN
Usamos la cola del tema 42: 98, 183, 37, 122, 14, 124, 65, 67, identificadas como R1 a R8. Inicio 53, M=199 y dirección ascendente.
| Evento | Tipo e identidad | Desde → hasta | Distancia | Acumulado |
|---|---|---|---|---|
| 1 | Petición R7 | 53 → 65 | 12 | 12 |
| 2 | Petición R8 | 65 → 67 | 2 | 14 |
| 3 | Petición R1 | 67 → 98 | 31 | 45 |
| 4 | Petición R4 | 98 → 122 | 24 | 69 |
| 5 | Petición R6 | 122 → 124 | 2 | 71 |
| 6 | Petición R2 | 124 → 183 | 59 | 130 |
| 7 | Extremo, sin petición | 183 → 199 | 16 | 146 |
| 8 | Petición R3 | 199 → 37 | 162 | 308 |
| 9 | Petición R5 | 37 → 14 | 23 | 331 |
53 → 199: 146 cilindros
199 → 14: 185 cilindros
D_SCAN = (199 − 53) + (199 − 14) = 331 cilindros
Media = 331 / 8 = 41,375 cilindros por peticiónDespués de R5=14 no vamos a 0: ya se atendieron las ocho peticiones. Si un ejercicio pidiera terminar el barrido completo hasta 0, añadiría 14 cilindros y obtendría 345. Nuestra pregunta termina al concluir el trabajo pendiente.
6. C-SCAN: atender en un solo sentido
C-SCAN conserva un sentido de servicio. En dirección ascendente atiende de menor a mayor, llega a M y retorna a 0 sin atender durante ese trayecto. Desde 0 comienza otro barrido ascendente. Con dirección descendente se invierten los extremos y el orden.
mientras queden solicitudes:
si hay una en la posición actual o por delante:
atender la más próxima en el sentido de servicio
si no:
mover al extremo de ese sentido
retornar al extremo opuesto sin atender durante el viaje
mantener el sentido de servicioEl retorno cambia el sentido del movimiento físico, pero no el sentido del siguiente barrido de servicio. Por eso una petición que se cruza durante el retorno sigue pendiente. Al llegar al extremo opuesto, una petición situada allí puede ser atendida con distancia cero.
La circularidad busca organizar el paso de servicio en un único sentido. No significa que el recorrido sea menor que el de SCAN para toda cola. Las notas de almacenamiento de la Universidad de Illinois Chicago presentan SCAN, C-SCAN y LOOK como variantes de recorrido.
7. Traza completa de C-SCAN
Con inicio 53 y sentido ascendente, las primeras seis atenciones coinciden con SCAN. La diferencia aparece al alcanzar el extremo superior.
| Evento | Tipo e identidad | Desde → hasta | Distancia | Acumulado |
|---|---|---|---|---|
| 1 | Petición R7 | 53 → 65 | 12 | 12 |
| 2 | Petición R8 | 65 → 67 | 2 | 14 |
| 3 | Petición R1 | 67 → 98 | 31 | 45 |
| 4 | Petición R4 | 98 → 122 | 24 | 69 |
| 5 | Petición R6 | 122 → 124 | 2 | 71 |
| 6 | Petición R2 | 124 → 183 | 59 | 130 |
| 7 | Extremo | 183 → 199 | 16 | 146 |
| 8 | Salto sin servicio | 199 → 0 | 199 | 345 |
| 9 | Petición R5 | 0 → 14 | 14 | 359 |
| 10 | Petición R3 | 14 → 37 | 23 | 382 |
D_CSCAN = (199 − 53) + (199 − 0) + (37 − 0)
= 146 + 199 + 37 = 382 cilindros
Salto J = 199 cilindros
Subtotal sin salto = 382 − 199 = 183 cilindros
Media física = 382 / 8 = 47,75 cilindros por petición183 es un subtotal útil para localizar una omisión, pero no el total físico. Tampoco se atienden R3=37 o R5=14 durante el viaje 199 → 0. Hacerlo transformaría la regla de servicio.
8. LOOK: invertir en la última petición
LOOK mantiene el barrido direccional, pero examina si quedan solicitudes por delante. Cuando no hay más en ese sentido, invierte desde la última atendida, sin completar el viaje a un extremo sin trabajo.
53 → 65 → 67 → 98 → 122 → 124 → 183 → 37 → 14
Distancias: 12 + 2 + 31 + 24 + 2 + 59 + 146 + 23
D_LOOK = (183 − 53) + (183 − 14) = 299 cilindros
Media = 299 / 8 = 37,375 cilindros por peticiónEl giro ocurre en 183, no en 199. Ahorra 16 cilindros de ida al extremo y otros 16 del regreso: SCAN − LOOK = 331 − 299 = 32. Cambiar M de 199 a 399 no modifica esta traza LOOK si la cola y el inicio se mantienen.
Si no hay solicitudes por delante al comenzar, LOOK invierte inmediatamente sin mover el cabezal antes. No selecciona la más cercana entre ambos lados mientras sí queda trabajo en su dirección.
C-LOOK sería la variante circular que retorna entre las solicitudes extremas pendientes. Es una política distinta: en este tema el retorno de C-SCAN se hace entre 0 y M, no entre el mínimo y máximo solicitados.
9. Repetir el cálculo hacia cilindros menores
La dirección inicial cambia el orden y los totales. No la inferimos de cuál petición queda más cerca. Si el enunciado da una posición anterior del cabezal, debe explicar que se conserva ese sentido; aquí la dirección es un argumento explícito.
| Política | Ruta descendente desde 53 | Recorrido |
|---|---|---|
| SCAN | 53 → 37 → 14 → [0] → 65 → 67 → 98 → 122 → 124 → 183 | 53 + 183 = 236 |
| C-SCAN | 53 → 37 → 14 → [0] → [199, salto] → 183 → 124 → 122 → 98 → 67 → 65 | 53 + 199 + 134 = 386 |
| LOOK | 53 → 37 → 14 → 65 → 67 → 98 → 122 → 124 → 183 | 39 + 169 = 208 |
Los corchetes marcan movimientos sin petición propia. SCAN descendente y SSTF del tema 42 suman ambos 236, pero tienen rutas distintas. Un total igual no identifica la política ni garantiza el mismo orden de finalización.
Para comprobar ambos sentidos podemos reflejar las coordenadas: transformar c en M−c, transformar también el inicio y cambiar la dirección. Las distancias absolutas no cambian. Esta simetría será una propiedad útil para el verificador.
10. Comparar distancia, tiempos y equidad
| Política | Ascendente | Descendente | Regla de continuación |
|---|---|---|---|
| SCAN | 331 | 236 | Llegar al extremo e invertir. |
| C-SCAN | 382 | 386 | Retornar al extremo opuesto y conservar sentido de servicio. |
| LOOK | 299 | 208 | Invertir al terminar las solicitudes del sentido actual. |
Para esta cola gana LOOK descendente en recorrido. No se deduce de ello una política universalmente superior: dirección, posición inicial, carga y objetivo influyen. C-SCAN organiza las visitas de servicio de forma circular aunque necesite más movimiento en este ejemplo.
Con solicitudes mantenidas durante una operación continua, un barrido bidireccional visita posiciones interiores al ir y al volver, mientras las posiciones extremas se visitan en los giros. C-SCAN organiza una visita de servicio por ciclo en su único sentido. Esto motiva su interés por la regularidad espacial; no acredita iguales respuestas para todas las cargas ni para la cola finita del ejemplo.
El recorrido sigue medido en cilindros. Si definimos servicio temporal como a × distancia más b por petición, el tiempo hasta la última finalización es aD + nb, incluyendo los viajes sin servicio en D. Por ejemplo, con a=0,05 ms/cilindro, b=1 ms y n=8, SCAN ascendente cuesta 24,55 ms; C-SCAN, 27,1 ms; LOOK, 22,95 ms. Es un modelo lineal supuesto, no una medida de hardware.
Para calcular espera y respuesta de cada solicitud se debe conservar la traza temporal completa, incluidas las fases de reposicionamiento. Dividir D por n no da esos tiempos.
11. Duplicados, extremos y nuevas llegadas
Casos de borde en una cola estática
- Dos solicitudes del mismo cilindro se atienden por índice de ingreso y ambas cuentan, aunque el segundo tramo mida cero.
- Si hay peticiones en el inicio, se atienden antes de comenzar el barrido.
- Si una petición está en el extremo hacia el que avanzamos, atenderla ya sitúa allí al cabezal; no se agrega otro evento extremo de distancia cero.
- Si todas las peticiones quedan detrás, SCAN alcanza primero el extremo de su dirección; C-SCAN además retorna al opuesto; LOOK invierte inmediatamente.
- Si la última petición termina antes del extremo, no se sigue viajando tras vaciar la cola.
Ejemplo mínimo: inicio 50, M=199, cola 40 y dirección ascendente. SCAN viaja 50 → 199 → 40: 308 cilindros. C-SCAN hace 50 → 199 → 0 → 40: 388. LOOK hace 50 → 40: 10. Una sola petición no hace equivalentes a las tres bajo la convención direccional elegida.
Qué cambia con nuevas llegadas
La implementación de este tema es estática: no incorpora peticiones mientras recorre. Una versión dinámica debe definir qué llegadas pueden entrar al barrido actual, cuándo se decide invertir y cuánto trabajo puede atenderse en un cilindro antes de continuar.
La dirección por sí sola no prueba ausencia de inanición. Si se permiten llegadas ilimitadas al cilindro actual y se atienden todas antes de avanzar, el cabezal podría quedarse allí indefinidamente. Una regla posible es atender solo el lote presente al llegar y reservar las nuevas para otra pasada. Las notas de planificación de Wisconsin describen este problema y la necesidad de limitar el servicio local.
Para afirmar una cota de espera hacen falta supuestos adicionales sobre carga admitida, duración de servicios y admisión a cada pasada. Un planificador real también debe considerar prioridades y plazos; no basta con dibujar una flecha de avance.
12. Programa en C: tres políticas, una traza explícita
Guarda barridos-disco.c. Recibe política scan|cscan|look, dirección up|down, mayor cilindro, inicio y de 1 a 100 solicitudes. Las coordenadas son enteros decimales de 0 a M, con M de 1 a 1000000. Devuelve 2 ante uso o valores inválidos y 0 al completar la traza.
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#define CAPACIDAD 100
#define LIMITE UINT32_C(1000000)
struct peticion { uint32_t cilindro; int atendida; };
struct traza {
uint32_t actual;
uint64_t total, salto;
int paso;
};
static int decimal(const char *s, uint32_t *valor)
{
uint32_t n = 0;
if (!*s) return -1;
for (; *s; ++s) {
if (*s < '0' || *s > '9') return -1;
uint32_t d = (uint32_t)(*s - '0');
if (n > (LIMITE - d) / 10) return -1;
n = n * 10 + d;
}
*valor = n;
return 0;
}
static uint32_t distancia(uint32_t a, uint32_t b)
{
return a >= b ? a - b : b - a;
}
static void emitir(struct traza *t, const char *tipo, int id, uint32_t destino)
{
uint32_t d = distancia(t->actual, destino);
t->total += d;
if (!strcmp(tipo, "salto")) t->salto += d;
printf("%d,%s,%d,%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu64 "\n",
++t->paso, tipo, id, t->actual, destino, d, t->total);
t->actual = destino;
}
int main(int argc, char **argv)
{
uint32_t maximo, inicial;
if (argc < 6 || argc > CAPACIDAD + 5 ||
(strcmp(argv[1], "scan") && strcmp(argv[1], "cscan") &&
strcmp(argv[1], "look")) ||
(strcmp(argv[2], "up") && strcmp(argv[2], "down")) ||
decimal(argv[3], &maximo) || maximo == 0 ||
decimal(argv[4], &inicial) || inicial > maximo) {
fprintf(stderr, "Uso: %s scan|cscan|look up|down maximo inicio c1 [c2 ...]\n",
argv[0]);
return 2;
}
struct peticion cola[CAPACIDAD] = {0};
int n = argc - 5;
for (int i = 0; i < n; ++i) {
if (decimal(argv[i + 5], &cola[i].cilindro) || cola[i].cilindro > maximo) {
fprintf(stderr, "Cilindro invalido en R%d\n", i + 1);
return 2;
}
}
int direccion = !strcmp(argv[2], "up") ? 1 : -1;
int circular = !strcmp(argv[1], "cscan");
int look = !strcmp(argv[1], "look");
int restantes = n;
struct traza t = {inicial, 0, 0, 0};
puts("paso,tipo,id,desde,hasta,distancia,acumulado");
while (restantes) {
int mejor = -1;
for (int i = 0; i < n; ++i) {
uint32_t c = cola[i].cilindro;
if (cola[i].atendida || (direccion > 0 && c < t.actual) ||
(direccion < 0 && c > t.actual)) continue;
if (mejor == -1 || distancia(t.actual, c) <
distancia(t.actual, cola[mejor].cilindro)) mejor = i;
}
if (mejor != -1) {
emitir(&t, "peticion", mejor + 1, cola[mejor].cilindro);
cola[mejor].atendida = 1;
--restantes;
} else {
if (!look) {
uint32_t extremo = direccion > 0 ? maximo : 0;
if (t.actual != extremo) emitir(&t, "extremo", 0, extremo);
}
if (circular) emitir(&t, "salto", 0, direccion > 0 ? 0 : maximo);
else direccion = -direccion;
}
}
printf("TOTAL=%" PRIu64 "\nSALTO=%" PRIu64 "\nPETICIONES=%d\nMEDIA=%.6f\n",
t.total, t.salto, n, (double)t.total / n);
return 0;
}No se abre ningún archivo de datos ni dispositivo. La salida CSV conserva los identificadores originales; los movimientos sin petición usan id=0. TOTAL incluye todo el recorrido y SALTO identifica su parte circular. Se valida toda la entrada antes de imprimir una traza.
13. Revisar selección, aritmética y terminación
El selector solo considera candidatos en el sentido de avance, incluida la posición actual. Recorre el arreglo en orden de ingreso y reemplaza al mejor únicamente ante una distancia estrictamente menor; los duplicados mantienen así su orden.
Cuando no hay candidato y quedan solicitudes, todas están al otro lado. LOOK invierte; SCAN alcanza su extremo e invierte; C-SCAN alcanza el extremo, retorna y mantiene su sentido de servicio. En la siguiente selección hay trabajo alcanzable. Como la cola es estática y cada servicio reduce restantes, el proceso termina.
La distancia resta el menor del mayor antes de sumar en uint64_t. No se resta primero en un tipo sin signo esperando que abs arregle un subdesbordamiento. El analizador comprueba su límite antes de multiplicar por diez.
Con n≤100 y coordenadas hasta 1000000, hay a lo sumo n eventos de petición y dos movimientos auxiliares para la cola estática de C-SCAN. El acumulador elegido deja margen. M nunca es cero, por lo que un retorno entre extremos no puede ser un ciclo de distancia cero.
Esta implementación explora n posiciones en cada selección: O(n²) para la cola completa y O(n) de almacenamiento. Una implementación estática también puede ordenar por cilindro e identidad y recorrer las particiones en O(n log n). Esa segunda forma será nuestra referencia independiente.
14. Laboratorio con ambos sentidos y casos de borde
En una terminal Bash crea un directorio nuevo, guarda allí barridos-disco.c y compílalo. El laboratorio requiere compilador C y Python 3; no necesita imágenes, montajes ni permisos de administrador.
mkdir laboratorio43
cd laboratorio43
# Guardar aqui barridos-disco.c antes de continuar.
cc -std=c11 -O2 -Wall -Wextra -Wpedantic barridos-disco.c -o barridos-disco
for sentido in up down; do
for politica in scan cscan look; do
printf '\n%s %s\n' "$politica" "$sentido"
./barridos-disco "$politica" "$sentido" 199 53 98 183 37 122 14 124 65 67
done
doneLos totales deben ser 331, 382 y 299 en ascendente, y 236, 386 y 208 en descendente. Las seis ejecuciones deben informar PETICIONES=8. Solo C-SCAN presenta SALTO=199; las otras políticas informan cero.
./barridos-disco cscan up 199 53 53 53 0 199
./barridos-disco scan up 199 50 40
./barridos-disco cscan up 199 50 40
./barridos-disco look up 199 50 40
./barridos-disco scan up 199 50 60 70
./barridos-disco cscan up 199 50 60 70
./barridos-disco look up 199 50 60 70
./barridos-disco scan up 399 53 98 183 37 122 14 124 65 67
./barridos-disco cscan up 399 53 98 183 37 122 14 124 65 67
./barridos-disco look up 399 53 98 183 37 122 14 124 65 67En el primer caso, las dos solicitudes en 53 se conservan, 199 se atiende antes del salto y 0 después. En los casos 60,70, las tres políticas terminan en 70 con recorrido 20. Al aumentar M a 399 para la cola principal, SCAN suma 731, C-SCAN 782 y LOOK conserva 299.
Si guardas las salidas para compararlas, comprueba tanto las filas como los totales. El tiempo que tarda el ejecutable en imprimir no mide búsqueda mecánica; el laboratorio revisa decisiones y contabilidad del modelo.
15. Verificador independiente por particiones ordenadas
Ejecuta desde laboratorio43. La referencia separa las peticiones en iguales al inicio, por delante y por detrás, y ordena cada grupo. No repite el bucle de selección del programa C. Comprueba todos los eventos, identidades, duplicados, extremos, retornos y simetría por reflexión.
python3 - <<'PY'
import csv
import io
import math
import random
import subprocess
def referencia(politica, arriba, m, inicio, cola):
iguales = [(i + 1, c) for i, c in enumerate(cola) if c == inicio]
delante = [(i + 1, c) for i, c in enumerate(cola)
if (c > inicio if arriba else c < inicio)]
detras = [(i + 1, c) for i, c in enumerate(cola)
if (c < inicio if arriba else c > inicio)]
clave = lambda r: (r[1] if arriba else -r[1], r[0])
delante.sort(key=clave)
detras.sort(key=clave if politica == 'cscan' else
lambda r: (-r[1] if arriba else r[1], r[0]))
eventos = [('peticion', i, c) for i, c in iguales + delante]
actual = eventos[-1][2] if eventos else inicio
if detras and politica != 'look':
extremo = m if arriba else 0
if actual != extremo:
eventos.append(('extremo', 0, extremo))
if politica == 'cscan':
eventos.append(('salto', 0, 0 if arriba else m))
eventos.extend(('peticion', i, c) for i, c in detras)
return eventos
def comprobar(politica, arriba, m, inicio, cola):
args = ['./barridos-disco', politica, 'up' if arriba else 'down',
str(m), str(inicio), *map(str, cola)]
r = subprocess.run(args, text=True, capture_output=True, check=True)
lineas = r.stdout.splitlines()
filas = list(csv.DictReader(io.StringIO('\n'.join(lineas[:-4]))))
esperados = referencia(politica, arriba, m, inicio, cola)
assert len(filas) == len(esperados)
actual, total, salto, ids = inicio, 0, 0, []
for paso, (fila, (tipo, identidad, destino)) in enumerate(zip(filas, esperados), 1):
d = abs(destino - actual)
total += d
if tipo == 'salto':
salto += d
if tipo == 'peticion':
ids.append(identidad)
assert fila['tipo'] == tipo
assert [int(fila[k]) for k in ('paso', 'id', 'desde', 'hasta', 'distancia', 'acumulado')] == [
paso, identidad, actual, destino, d, total]
actual = destino
resumen = dict(s.split('=') for s in lineas[-4:])
assert sorted(ids) == list(range(1, len(cola) + 1))
assert int(resumen['TOTAL']) == total
assert int(resumen['SALTO']) == salto
assert int(resumen['PETICIONES']) == len(cola)
assert math.isclose(float(resumen['MEDIA']), total / len(cola), abs_tol=1e-6)
return total
principal = [98, 183, 37, 122, 14, 124, 65, 67]
for politica, up, down in [('scan', 331, 236), ('cscan', 382, 386), ('look', 299, 208)]:
assert comprobar(politica, True, 199, 53, principal) == up
assert comprobar(politica, False, 199, 53, principal) == down
assert comprobar(politica, True, 199, 50, [60, 70]) == 20
assert comprobar(politica, True, 199, 50, [50, 50]) == 0
comprobar(politica, True, 199, 53, [53, 53, 0, 199])
comprobar(politica, False, 199, 0, [0, 199, 199])
comprobar(politica, True, 199, 199, [0, 0, 199])
rng = random.Random(43)
for n in (1, 2, 8, 30, 100):
for _ in range(4):
m = rng.choice([1, 199, 1000000])
inicio = rng.randrange(m + 1)
cola = [rng.randrange(m + 1) for _ in range(n)]
for politica in ('scan', 'cscan', 'look'):
for arriba in (True, False):
total = comprobar(politica, arriba, m, inicio, cola)
reflejado = comprobar(politica, not arriba, m, m - inicio,
[m - c for c in cola])
assert total == reflejado
for args in ([], ['otro', 'up', '199', '53', '14'],
['scan', 'otro', '199', '53', '14'],
['look', 'up', '0', '0', '0'],
['scan', 'up', '199', '200', '14'],
['cscan', 'up', '199', '53', '-1'],
['scan', 'up', '199', '53', '200'],
['scan', 'up', '199', '53', '1.5'],
['scan', 'up', '199', '53', ''],
['scan', 'up', '199', '53', '99999999999999999999'],
['scan', 'up', '199', '53'],
['scan', 'up', '199', '53', *(['0'] * 101)]):
r = subprocess.run(['./barridos-disco', *args], capture_output=True, text=True)
assert r.returncode == 2 and not r.stdout, (args, r.returncode)
print('OK: politicas, eventos, retornos, identidades, reflexion y rechazos')
PYEl éxito verifica el contrato estático y sus casos probados. No demuestra una garantía de espera para llegadas dinámicas ni convierte las distancias en tiempos físicos de un disco.
16. Simuladores de barridos y límites
Comparar políticas y revisar cada evento
Introduce de 1 a 100 cilindros separados por comas. El resumen calcula las tres políticas con el mismo inicio, dirección y límite. Elige una para ver su traza: las líneas discontinuas identifican el retorno sin servicio. El eje horizontal muestra cilindros y el vertical eventos, sin escala temporal.
Un mismo trabajo, tres barridos
| Política | Recorrido total | Parte de retorno | Media por petición |
|---|
| Evento | Tipo | Identidad | Desde | Hasta | Distancia | Acumulado |
|---|
¿Qué cambia si el disco tiene otro límite?
Se mantiene la cola principal, inicio 53 y sentido ascendente. Solo cambia M, que debe ser al menos 183. El simulador contrasta el límite mínimo, 199 y tu valor. LOOK conserva el mismo recorrido; SCAN y C-SCAN incorporan los nuevos trayectos a extremos.
Auditar extremos y retorno circular
| M | SCAN: total | C-SCAN: total | LOOK: total | Retorno C-SCAN |
|---|
17. Diagnóstico y resumen
| Observación | Qué revisar |
|---|---|
| SCAN y LOOK generan siempre la misma ruta. | Comprobar si SCAN omitió el extremo antes de invertir con trabajo al otro lado. |
| C-SCAN suma 183 en la cola ascendente principal. | Se omitieron los 199 cilindros del retorno: el total físico es 382. |
| Se usa 200 como distancia entre 0 y 199. | Se confundió cantidad de posiciones con distancia entre extremos. |
| La cola queda vacía y aún aparecen movimientos. | Revisar la convención de finalización; aquí se termina tras la última petición. |
| Una petición se atiende durante el retorno C-SCAN. | Ese trayecto debe carecer de servicio hasta alcanzar el extremo opuesto. |
| Se eliminó una solicitud repetida en el mismo cilindro. | Conservar identidades; un tramo cero también corresponde a un servicio. |
| Se promete una espera máxima solo por usar barridos. | Definir carga, admisión por pasada y duración de los servicios antes de afirmar una cota. |
- La dirección inicial y el límite del disco forman parte del problema.
- SCAN alcanza el extremo antes de invertir cuando aún queda trabajo al otro lado.
- C-SCAN retorna al extremo opuesto sin servicio durante ese viaje y mantiene el sentido de atención.
- LOOK invierte cuando termina el trabajo por delante, sin visitar extremos vacíos.
- El retorno circular cuenta como desplazamiento físico en el contrato del tema.
- Servicios y movimientos auxiliares deben distinguirse para no contar peticiones inexistentes.
- El recorrido se detiene al atender la última solicitud, sin completar barridos vacíos.
- La equidad dinámica requiere reglas de admisión y supuestos adicionales; una traza estática no basta para acreditarla.
18. Preguntas de repaso y práctica
1. ¿Qué estado se agrega respecto de SSTF?
La dirección de servicio: no se elige libremente entre ambos lados en cada decisión.
2. ¿Dónde invierte SCAN?
En el extremo del sentido actual, si queda trabajo al otro lado. La simulación termina si ya no hay peticiones.
3. ¿Dónde invierte LOOK?
En la última solicitud del sentido actual; si no hay ninguna por delante, puede invertir sin desplazarse.
4. ¿Qué distingue el retorno de C-SCAN?
Se desplaza al extremo opuesto sin atender durante el viaje y luego conserva el sentido de servicio.
5. ¿Cuánto mide el retorno entre 0 y 199?
199 cilindros, aunque el rango contenga 200 posiciones.
6. ¿Se suma ese retorno al recorrido?
Sí. Aquí se cuenta todo el movimiento físico.
7. ¿Cuáles son los totales ascendentes del ejemplo?
SCAN: 331; C-SCAN: 382; LOOK: 299 cilindros.
8. ¿Y los descendentes?
SCAN: 236; C-SCAN: 386; LOOK: 208 cilindros.
9. ¿Por qué LOOK ascendente ahorra 32 respecto de SCAN?
Evita los 16 cilindros de 183 a 199 y los mismos 16 del regreso.
10. ¿Por qué no se lleva SCAN hasta 0 después de atender 14?
Porque 14 es la última petición de esa ruta y nuestro horizonte termina al completar el trabajo.
11. ¿Qué representa un evento extremo?
Un desplazamiento auxiliar hasta un límite; no una nueva petición atendida.
12. ¿Qué pasa si existe una petición en el extremo?
Se atiende con su identidad; si ya estamos allí, no se agrega otro evento extremo de distancia cero.
13. ¿Se conservan solicitudes duplicadas?
Sí. Se desempatan por ingreso y cada una cuenta, incluso si no requiere desplazamiento.
14. ¿C-SCAN siempre recorre menos que SCAN?
No. En el ejemplo principal recorre más; su organización circular responde a otro criterio.
15. ¿Cambiar M modifica siempre LOOK?
No. Si solo cambia un límite exterior que sigue conteniendo la misma cola y el mismo inicio, la traza LOOK se conserva.
16. ¿Qué dato falta si solo se proporciona la cola y el inicio?
La dirección y, para SCAN/C-SCAN, los límites, además de la convención de contabilidad y finalización.
17. ¿Un barrido garantiza por sí solo ausencia de inanición?
No. Una versión dinámica debe limitar la admisión y el servicio local para impedir bloqueos por nuevas llegadas.
18. ¿Qué verifica reflejar c en M−c?
La simetría entre ambos sentidos: reflejar también el inicio e invertir dirección conserva las distancias.
19. ¿D/n es una latencia media?
No. Es recorrido medio por petición; se necesita un modelo temporal adicional para obtener tiempos.
20. ¿El programa configura el planificador del sistema?
No. Solo calcula trazas estáticas sobre coordenadas didácticas y escribe los resultados.
Para practicar
- Reproduce las tres rutas ascendentes y distingue cada servicio de los movimientos auxiliares.
- Calcula ambas direcciones para inicio 100, M=199 y cola 10,190,20,180.
- Explica por qué el total descendente de SCAN coincide con SSTF del tema anterior, aunque las rutas difieran.
- Elimina el retorno del cálculo C-SCAN y localiza exactamente el subtotal que obtienes.
- Prueba cola 40 desde 50 en sentido ascendente y verifica los resultados 308, 388 y 10.
- Agrega peticiones en 0, M y el inicio; conserva todos sus identificadores.
- Cambia M de 199 a 399 y comprueba los totales 731, 782 y 299 de la cola principal ascendente.
- Refleja una carga pequeña en M−c e invierte el sentido; compara todos los tramos.
- Compila con las advertencias indicadas y ejecuta el verificador.
- Con a=0,05 ms/cilindro y b=1 ms/petición, construye los tiempos de finalización de las ocho solicitudes en cada ruta.
- Diseña una regla de admisión por pasada para una versión dinámica y explica cómo trataría llegadas al cilindro actual.
- Describe qué cambiaría para agregar C-LOOK, distinguiendo el retorno entre solicitudes del retorno entre extremos del disco.
En el tema 44 conectaremos estos modelos con los planificadores de Linux y con dispositivos SSD y NVMe, donde la geometría, el paralelismo y las colas requieren otros criterios.