Algoritmos de gestión de buffers para dispositivos de bloques en sistemas operativos

El mecanismo básico implica asignar buffers para bloques específicos (dispositivo, bloque). Al leer, si el buffer ya existe con datos válidos, se reutiliza directamente. De lo contrario, se asigna un buffer libre, se carga el bloque del disco, y se atiende la solicitud. Los buffers marcados como sucios (dirty) no se escriben inmediatamente; solo se sincronizan con el disco cuando son reasignados, permitiendo reutilización y reduciendo E/S física.

Para escrituras, se distinguen operaciones síncronas y asíncronas. Las escrituras asíncronas diferidas marcan el buffer como sucio y lo liberan a la caché, optimizando el rendimiento. Ejemplos simplificados en código muestran estas operaciones:


BUFFER *leer_bloque(int dispo, int bloque) {
    BUFFER *bp = obtener_bloque(dispo, bloque);
    if (bp->datos_válidos) {
        return bp;
    }
    bp->tipo_operación = LECTURA;
    iniciar_entrada_salida(bp);
    esperar_completitud_entrada_salida();
    return bp;
}

void escritura_síncrona(BUFFER *bp) {
    bp->tipo_operación = ESCRITURA;
    iniciar_entrada_salida(bp);
    esperar_completitud_entrada_salida();
    liberar_buffer(bp);
}

void escritura_diferida(BUFFER *bp) {
    marcar_buffer_sucio(bp);
    liberar_buffer(bp);
}

El controlador de dispositivos mantiene una cola de E/S para gestionra las solicitudes pendientes. Al completarse una operración, un manejador de interrupciones atiende la cola y activa el siguiente buffer. Ejemplo del manejo de interrupciones:


void manejador_interrupción() {
    BUFFER *bp = desencolar(cola_e_s_dispositivo);
    if (bp->tipo_operación == ASÍNCRONO) {
        liberar_buffer(bp);
    } else {
        desbloquear_proceso(bp);
    }
    if (!cola_vía(cola_e_s_dispositivo)) {
        emitir_comando_entrada_salida(primer_elemento(cola_e_s_dispositivo));
    }
}

En el algoritmo clásico de Unix, la gestión de buffers utiliza listas de buffers libres, listas de dispositivos y colas de E/S. Cada buffer tiene una estructura con encabezado y datos, y se asigna desde una lista libre. Sin embargo, este algoritmo tiene limitaciones: bucles de reintento que generan ineficiencia, efectos de caché impredecibles, posible inanición de procesos y dependencia de mecanismos de dormir/activar que no son óptimos para sistemas multiprocesador.

Para mejorar, se propone un algoritmo basado en semáforos, que utiliza operaciones P/V para sincronización. Los semáforos contadores representan recursos disponibles, como buffers libres, y garantizan exclusión mutua sin reintento. Definiciones clave incluyen:


BUFFER buffers[N];
SEMAPHORE libres = N;
SEMAPHORE bloqueo_buffer[N] = {1};

Este enfoque asegura unicidad de buffers, evita reintentos innecesarios, mejora el efecto de caché al retener buffers en uso, y previene bloqueos e inanición mediante un orden consistente de adquisición de semáforos.

En implementaciones prácticas, como sistemas simulados, la arquitectura puede incluir un gestor de buffers, controladores de disco virtuales y manejo de interrupciones mediante señales. Los buffers se gestionan con funciones específicas, y los dispositivos virtuales emulan operaciones de bloque usando archivos del sistema host.

Etiquetas: unix gestión de buffers dispositivos de bloques E/S semáforos

Publicado el 6-12 04:08