Monitor
Monitor
Un cerrojo y cero o más variables condición que gestionan el acceso concurrente a datos compartidos.
NOTA: En los libros de Tanenbaum y Silberschatz se describe a los monitores como construcciones lingüísticas en forma de tipo abstracto de datos.
Cuando se llama a una operación del tipo monitor, se adquiere automáticamente el cerrojo asociado. Sin embargo, pocos lenguajes implementan
monitores como TADs (la única excepción moderna es Ada95). En Nachos y otros sistemas operativos modernos, los monitores se implementan a partir
de llamadas a cerrojos y variables condición.
Cerrojos
Un cerrojo proporciona exclusión mutua en el acceso a datos compartidos. El cerrojo es una variable de dos estados (libre y ocupado) y tiene dos
operaciones públicas:
Lock::Acquire
Espera a que el cerrojo esté libre y lo adquiere.
Lock::Release
Libera el cerrojo; si había alguien esperando en Acquire, se lo entrega a alguno de los procesos que esperan.
Inicialmente, se considera que el cerrojo está libre. Un cerrojo no es más que un semáforo binario inicializado a cierto.
Para acceder a datos
compartidos en exclusión mutua, se usa un cerrojo. Antes de usar los datos compartidos se llama a Acquire y tras manipular los datos, se libera
el cerrojo con Release:
Ejemplo simple: una lista con sincronización:
Lock cerrojo;
InsertaEnCola() {
cerrojo.Acquire();
añade un elemento en la cola;
cerrojo.Release();
}
ExtraeDeCola() {
cerrojo.Acquire();
if (algo en la cola)
extrae(cosa);
cerrojo.Release();
return cosa;
}
El ejemplo anterior nos muestra un problema que los cerrojos no son capaces de resolver. La rutina ExtraeDeCola debería esperar a que hubiera algún
elemento en la cola. Si lo que hacemos es dormir al hilo hasta que alguien deposite un elemento en la cola, resulta que el programa se bloquea,
ya que al estar retenido el cerrojo, ningún otro hilo puede manipular la cola. Por tanto hay que liberar el cerrojo antes de esperar. Una posible
solución sería:
ExtraeDeCola() {
cerrojo.Acquire();
while (cola vacía)
{
cerrojo.Release();
cerrojo.Acquire();
}
extrae(cosa);
cerrojo.Release();
return cosa;
}
Esta solución funciona, pero utiliza espera activa: el hilo está continuamente entrando y saliendo de la sección crítica para revisar si la cola
está vacía. La idea de las variables condición es tener un mecanismo que permita a un proceso abandonar una sección crítica y a la misma vez
quedarse bloqueado en espera de una condición que alguien le debe notificar.