2.2.2. Utilización de los semáforos
Material de estudio basado en la edición de 2014. Borrador pendiente de revisión editorial independiente.
Utilización de los Semáforos
Resumen
Los semáforos se utilizan en tres escenarios principales: exclusión mutua, contador de recursos y sincronización entre procesos.
1. Exclusión mutua en la sección crítica
Protocolo:
- Inicializar el semáforo con valor 1 (indica que no hay proceso en la sección crítica).
- El proceso ejecuta
sem_wait(exclusion)antes de entrar. - El proceso ejecuta
sem_signal(exclusion)al salir.
Ejemplo: variable trabajo_pendiente
semaphore exclusion;
sem_init(exclusion, 1);
/* Proceso usuario */
sem_wait(exclusion);
trabajo_pendiente = trabajo_pendiente + 1;
sem_signal(exclusion);
/* Proceso gestor */
while (cierto) {
while (trabajo_pendiente == 0); /* espera activa */
sem_wait(exclusion);
trabajo_pendiente = trabajo_pendiente - 1;
sem_signal(exclusion);
/* Enviar trabajo a la impresora */
}
Escenario de ejecución (T0–Tn):
- T0: semáforo = 1, sin procesos creados.
- T1: P1 ejecuta
sem_wait, semáforo = 0. P1 entra en sección crítica. P2, P3 y G esperan. - P1 ejecuta
sem_signal→ semáforo = 1. Cualquiera de los procesos puede entrar. - P3 entra → semáforo = 0. Cuando sale, vuelve a 1.
- Posible inanición: si un proceso siempre obtiene el semáforo antes que otros, éstos pueden esperar indefinidamente.
Granularidad de un semáforo:
- Granularidad baja: semáforos diferentes para zonas críticas diferentes → aumenta la concurrencia.
- Granularidad alta: un mismo semáforo para varias zonas críticas independientes → reduce la concurrencia.
2. Contador de recursos disponibles
- Inicializar el semáforo con el número inicial de recursos disponibles.
sem_wait: decrementa si hay recursos disponibles; si no, espera.sem_signal: incrementa cuando un proceso libera un recurso.
Ejemplo simplificado de trabajo_pendiente:
semaphore trabajos_pendientes;
sem_init(trabajos_pendientes, 0);
/* Proceso usuario */
sem_signal(trabajos_pendientes);
/* Proceso gestor */
sem_wait(trabajos_pendientes);
El contador del semáforo refleja el número de trabajos pendientes. El gestor se bloquea (no espera activa) si no hay trabajos.
3. Sincronización entre procesos
Un semáforo implementa sincronización donde un proceso espera autorización de otro.
Protocolo:
- Inicializar el semáforo con valor 0.
- El proceso que espera autorización ejecuta
sem_wait(sync). - El proceso que autoriza ejecuta
sem_signal(sync).
semaphore sync;
sem_init(sync, 0);
/* Proceso que espera */
sem_wait(sync);
/* Continúa solo después del sem_signal */
/* Proceso que autoriza */
sem_signal(sync);
Ideas clave
- Exclusión mutua: semáforo inicializado en 1, wait antes y signal después de la sección crítica.
- Contador de recursos: semáforo inicializado en N, wait para consumir y signal para liberar.
- Sincronización: semáforo inicializado en 0, un proceso espera y otro autoriza.
- La inanición puede ocurrir si la selección del proceso en espera no es equitativa (FIFO la evita).
- La granularidad baja (semáforos por zona crítica) es preferible para maximizar concurrencia.