Diferencia entre revisiones de «Semáforos»
(→Semáforos) |
(→Semáforos) |
||
Línea 25: | Línea 25: | ||
</source> | </source> | ||
− | En el pseudocódigo anterior, se puede añadir un proceso o un hilo. | + | En el pseudocódigo anterior, se puede añadir a la lista un proceso o un hilo. |
Nótese que siempre que queramos forzar una transición de un proceso a estado bloqueado, tenemos que hacer que dicho proceso realice una operación ''down'' sobre un semáforo cuyo contador vale cero. | Nótese que siempre que queramos forzar una transición de un proceso a estado bloqueado, tenemos que hacer que dicho proceso realice una operación ''down'' sobre un semáforo cuyo contador vale cero. |
Revisión del 20:28 16 nov 2012
Contenido
Planificador de procesos: Diagrama de estados simplicado
Para comprender apropiadamente cómo funcionan los semáforos es importante recordar cómo funciona el diagrama de estados de los procesos
Semáforos
Los semáforos son un mecanismo de sincronización de procesos inventados por Edsger Dijkstra en 1965. Los semáforos permiten al programador asistir al planificador del sistema operativo en su toma de decisiones de manera que permiten sincronizar la ejecución de dos o más procesos. A diferencia de los cerrojos, los semáforos nos ofrecen un mecanismo de espera no ocupada.
Los semáforos son un tipo de datos que están compuestos por dos atributos:
- Un contador, que siempre vale >= 0.
- Una lista de procesos(lista formada por el PCB de cada proceso), inicialmente vacía.
Y disponen de dos operaciones básicas que pasamos a describir en pseudocódigo:
down(semáforo s)
{
si s.contador == 0:
añade proceso a s.lista
proceso a estado bloqueado
sino:
s.contador--
}
En el pseudocódigo anterior, se puede añadir a la lista un proceso o un hilo.
Nótese que siempre que queramos forzar una transición de un proceso a estado bloqueado, tenemos que hacer que dicho proceso realice una operación down sobre un semáforo cuyo contador vale cero.
up(semáforo s)
{
si hay procesos en s.lista
retira proceso de s.lista
proceso a estado preparado
sino:
s.contador++
}
Nótese que una operación up sobre un semáforo en el que hay procesos en su lista resulta en que se retire uno de los procesos (el que más tiempo lleva en la lista), realizando éste la transición a estado preparado. Es un error frecuente pensar que una operación up resulte en que el proceso retirado de la lista pase a estado activo. Recuerde que las transiciones de estado activo a preparado y viceversa son siempre controladas por el planificador del sistema operativo.
Además, se disponen de un constructor y un destructor que permiten la creación y la liberación de un semáforo.
Ejemplo de uso de semáforos
Suponga el siguiente ejemplo en el que se quieren sincronizar dos hilos de un proceso, de manera que se dé la siguiente secuencia de ejecución: A, B, A, B, ... y así sucesivamente. El siguiente código resolvería el problema:
semaforo a = semaforo.create(1);
semaforo b = semaforo.create(0);
/* código del hilo A */
while (1) {
a.down();
printf("hilo A\n");
b.up();
}
/* código del hilo B */
while (1) {
b.down();
printf("hilo B\n");
a.up();
}
Tipos de semáforos
Dependiendo de la función que cumple el semáforo, vamos a diferenciar los siguientes tipos:
- Semáforo de exclusión mutua, inicialmente su contador vale 1 y permite que haya un único proceso simultáneamente dentro de la sección crítica.
- Semáforo contador, permiten llevar la cuenta del número de unidades de recurso compartido disponible, que va desde 0 hasta N.
- Semáforo de espera, generalmente se emplea para forzar que un proceso pase a estado bloqueado hasta que se cumpla la condición que le permite ejecutarse. Por lo general, el contador vale 0 inicialmente, no obstante, podría tener un valor distinto de cero.
Ventajas e inconvenientes
La principal ventaja de los semáforos frente a los cerrojos es que permiten sincronizar dos o más procesos de manera que no se desperdician recursos de CPU realizando comprobaciones continuadas de la condición que permite progresar al proceso.
Los inconvenientes asociados al uso de semáforos son los siguientes:
- Los programadores tienden a usarlos incorrectamente, de manera que no resuelven de manera adecuada el problema de concurrencia o dan lugar a interbloqueos.
- No hay nada que obligue a los programadores a usarlos.
- Los compiladores no ofrecen ningún mecanismo de comprobación sobre el correcto uso de los semáforos.
- Son independientes del recurso compartido al que se asocian.
Debido a estos inconvenientes, se desarrollaron los monitores.