← Sistemas de Archivos y E/SBloque 12 · Planificación de disco · Tema 43 de 50

Tema 43

SCAN, C-SCAN y LOOK

Mantener una dirección permite organizar el servicio como el recorrido de un ascensor. Compararemos cuándo invertir la marcha, cuándo regresar sin atender y cuándo evitar un extremo sin solicitudes. Usaremos la misma cola del tema anterior, una implementación en C, un verificador de trazas y dos simuladores que muestran cada desplazamiento.

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.

Tres maneras de continuar un barridoSCAN llega al extremo y vuelve atendiendo; C-SCAN llega al extremo y retorna al opuesto sin atender; LOOK invierte desde la última solicitud del sentido actual. SCANSolicitudes → extremo → vuelta con servicio C-SCANSolicitudes → extremo → retorno → mismo sentido LOOKSolicitudes → última del sentido → inversión
La regla de continuación determina movimientos que pueden no atender ninguna petición.

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.

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.

TipoIdentificadorSignificado
peticionR1, R2, etc.Viajar hasta esa solicitud y atenderla; puede tener distancia cero.
extremo0 en la salida C.Completar el trayecto hasta 0 o M sin atender una nueva solicitud.
salto0 en la salida C.Retorno físico de C-SCAN de un extremo al opuesto, sin servicio durante el viaje.
Contabilidad del recorrido físico
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.

Regla de SCAN para una cola estática
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ón

Con 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.

EventoTipo e identidadDesde → hastaDistanciaAcumulado
1Petición R753 → 651212
2Petición R865 → 67214
3Petición R167 → 983145
4Petición R498 → 1222469
5Petición R6122 → 124271
6Petición R2124 → 18359130
7Extremo, sin petición183 → 19916146
8Petición R3199 → 37162308
9Petición R537 → 1423331
Comprobación por tramos monótonos
53 → 199: 146 cilindros
199 → 14: 185 cilindros
D_SCAN = (199 − 53) + (199 − 14) = 331 cilindros
Media = 331 / 8 = 41,375 cilindros por petición

Despué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.

Regla de C-SCAN
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 servicio

El 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.

EventoTipo e identidadDesde → hastaDistanciaAcumulado
1Petición R753 → 651212
2Petición R865 → 67214
3Petición R167 → 983145
4Petición R498 → 1222469
5Petición R6122 → 124271
6Petición R2124 → 18359130
7Extremo183 → 19916146
8Salto sin servicio199 → 0199345
9Petición R50 → 1414359
10Petición R314 → 3723382
Retorno contado como movimiento físico
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ón

183 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.

Traza LOOK ascendente para la cola principal
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ón

El 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íticaRuta descendente desde 53Recorrido
SCAN53 → 37 → 14 → [0] → 65 → 67 → 98 → 122 → 124 → 18353 + 183 = 236
C-SCAN53 → 37 → 14 → [0] → [199, salto] → 183 → 124 → 122 → 98 → 67 → 6553 + 199 + 134 = 386
LOOK53 → 37 → 14 → 65 → 67 → 98 → 122 → 124 → 18339 + 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íticaAscendenteDescendenteRegla de continuación
SCAN331236Llegar al extremo e invertir.
C-SCAN382386Retornar al extremo opuesto y conservar sentido de servicio.
LOOK299208Invertir 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

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.

barridos-disco.c · movimientos y servicios separados
#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.

Compilar y comparar seis recorridos
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
done

Los 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.

Inicio repetido, extremos, un solo lado y límite mayor
./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 67

En 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.

Python 3 · referencia ordenada, casos conocidos y entradas inválidas
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')
PY

El é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íticaRecorrido totalParte de retornoMedia por petición
Ruta seleccionada · E: extremo; S: retorno sin servicio
Eventos de petición en verde, extremos y retorno en ámbar. El retorno circular usa línea discontinua.
EventoTipoIdentidadDesdeHastaDistanciaAcumulado

¿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

MSCAN: totalC-SCAN: totalLOOK: totalRetorno C-SCAN
Descomposición para el límite elegido

17. Diagnóstico y resumen

ObservaciónQué 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.

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

  1. Reproduce las tres rutas ascendentes y distingue cada servicio de los movimientos auxiliares.
  2. Calcula ambas direcciones para inicio 100, M=199 y cola 10,190,20,180.
  3. Explica por qué el total descendente de SCAN coincide con SSTF del tema anterior, aunque las rutas difieran.
  4. Elimina el retorno del cálculo C-SCAN y localiza exactamente el subtotal que obtienes.
  5. Prueba cola 40 desde 50 en sentido ascendente y verifica los resultados 308, 388 y 10.
  6. Agrega peticiones en 0, M y el inicio; conserva todos sus identificadores.
  7. Cambia M de 199 a 399 y comprueba los totales 731, 782 y 299 de la cola principal ascendente.
  8. Refleja una carga pequeña en M−c e invierte el sentido; compara todos los tramos.
  9. Compila con las advertencias indicadas y ejecuta el verificador.
  10. 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.
  11. 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.
  12. 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.