Semforos
Cecilia Hernndez 2013
Semforos
Primitiva de Sincronizacin propuesta por Dijkstra en 1968
Como parte de sistema THE Usados para exclusin mutua y planificacin De nivel ms alto que locks Wait(semaforo)
Decrementa semforo Bloquea hebra/proceso si el semforo es menor que cero, sino entonces permite a hebra/proceso continuar Operacion tambien llamada P(semaforo) o down(semaforo)
Variable atmica manipulada por dos operaciones
Signal(semforo)
Incrementa semforo en uno y si hay algn proceso/hebra esperando lo despierta Tambin llamada V(semaforo) o up(semaforo)
Valor de semforo puede ser mayor que 1
Inicializado en 1 es como lock.
Usado para exclusin mutua
Inicializado en N
Usado como contador atmico
Implementacin de Semforos
typedef struct { int value; struct hebra *L; } semaphore; void wait(semaphore S) { S.value--; if (S.value < 0){ agregar hebra a S.L; block(); } } void signal(semaphore S){ S.value++; if (S.value <= 0){ remover hebra T de S.L; wakeup(T); } }
Exclusin mutua vs planificacin
Exclusin mutua - Slo una hebra a la vez en SC - Puede ser cualquier hebra lock Seccin crtica unlock
Planificacin - Requerimiento de orden en ejecucin de hebras.
tiempo
Ejemplo planificacin
tiempo H1. imprime A
sem S1 = 0, S2 = 0 H1: H2: print A; wait(S1); signal(S1); print B; signal(S2);
H3: wait(S2); print C;
H2. imprime B H3. imprime C
Tipos de Semforos
Binarios (mutex) Garantizan exclusin mutua a recurso Slo una hebra/proceso puede accesar seccin crtica a la vez Contador de semforo inicializado en 1 Contadores Representan recursos con ms de una unidad disponible Permiten accesar recursos de acuerdo al nmero de recursos disponibles Contador es inicializado en N, donde N es la cantidad de unidades disponibles del recurso
Ejemplos Clsicos de Sincronizacin
Problema Productor/Consumidor
Un buffer en memoria con N slots disponibles
Necesita llevar cuenta de temes en buffer
Productor produce temes a ingresar al buffer Consumidor consume temes del buffer
C
Productor Agrega item usando puntero in out in
Consumidor Remueve item usando puntero out
Algoritmo Productor/Consumidor
int contador = 0; //indica nmero de items en buffer Tipo buffer[N]; int in = 0; int out = 0; Productor while (true) { /* produce un item en proxProd */ while (contador == N); //espera buffer[in] = proxProd; in = (in + 1) % N; contador++; } Consumidor while (true) { while (contador == 0); //espera proxCons = buffer[out]; out = (out + 1) % N; contador--; /* consume prodCons */ }
Cmo resolver problema?
Identificar restricciones inherentes al problema
Estado
compartido?
contador (consumidores y productores) Buffer
in ( productores) . Productores no pueden insertar en buffer lleno out ( consumidores). Consumidores no pueden extraer de buffer vaco
Posible resolver con locks? Si Posible resolver con semforos? Si
Cmo resolver problema?
Identificar estado compartido y restricciones de problema
Buffer de tamao limitado compartido entre productores y consumidores Productor escribe en buffer[in], in indica posicin de escritura en buffer Consumidor extrae de buffer[out], out indica posicin de extraccin de buffer Contador indica el nmero de elementos actuales en el buffer Mltiples productores deben manipular in, buffer[in] y contador atmicamente. Mltiples consumidores deben manipular out, buffer[out] y contador atmicamente Mltiples consumidores y productores deben manejar contador atmicamente
Solucin Productor/Consumidor usando locks
int contador = 0; //indica nmero de items en buffer char buffer[N]; int in = 0; int out = 0; lock_t mutex; Consumidor Productor while (true) { /* produce un item en proxProd */ lock(mutex); while(contador == N){ unlock(mutex); yield(); lock(mutex); } buffer[in] = proxProd; in = (in + 1) % N; contador++; unlock(mutex); } While(true){ lock(mutex); while(contador == 0){ unlock(mutex); yield(); lock(mutex); } proxCons = buffer[out]; out = (out + 1) % N; contador--; unlock(mutex); /* consume proxCons */ }
Solucin usando semforos
Identificar estado compartido y restricciones de problema
Ya presentadas Cuando buffer est lleno productores deben esperar a que exista una posicin vaca (generada por un consumidor) Cuando buffer esta vaco consumidores deben esperar a que exista un elemento en el buffer (generado por un productor) Acceso a buffer y contador debe realizarse atmicamente Mutex (inicializado en 1): para exclusin mutua de buffer, in, out y contador. Full (inicializado en 0). Para indicar cuntas posiciones llenas hay en el buffer Empty (inicializado en N). Para indicar cuantas posiciones vacas hay en el buffer
Especificar condiciones de espera y sealizacin
Identificar semforos para proveer sincronizacin
Proporcionar algoritmos
Solucin usando semforos
int contador = 0; //indica nmero de items en buffer char buffer[N]; int in = 0; int out = 0; sem mutex=1; sem vacio = N; sem lleno = 0; Productor while (true) { /* produce un item en proxProd */ wait(vacio); wait(mutex); buffer[in] = proxProd; in = (in + 1) % N; contador++; signal(mutex); signal(lleno); } Consumidor While(true){ wait(lleno); wait(mutex); proxCons = buffer[out]; out = (out + 1) % N; contador--; signal(mutex); signal(vacio); /* consume proxCons */ }
Ejemplos
Productor/consumidor usando pthreads y locks Productor/consumidor usando pthreads y semforos
http://www.inf.udec.cl/~chernand/so/ejemplos/prodconsLocks.cpp
http://www.inf.udec.cl/~chernand/so/ejemplos/prodconsSem.cpp
Problema lectores/escritor
Caso base de datos
Varios
lectores pueden accesar registro datos simultaneamente Slo un escritor puede escribir
L E Registro BD L
Cmo resolver problema?
Identificar estado compartido y restricciones de problema
Base de datos compartida
Mientras haya un lector un escritor no puede accesar base de datos Mientras exista un escritor en base de datos ningn otro escritor o lector puede accesarla
Identificar condiciones de espera y sealizacin
Si existe un escritor en BD otro escritor o lector debe esperar Cuando un escritor termina debe sealizar escritor o lector que espera Si podemos tener varios lectores debemos contarlos, para saber cuando existe uno
Si hay uno leyendo y llegan otros, otros tambien pueden leer Si solo hay uno y sale puede haber un escritor esperando accesar BD
Qu semforos necesitamos
Uno inicializado en 1 como mutex para manejar contador de lectores Uno tipo mutex para escritor y primer lector
Algoritmo usando semforos
sem mutex=1; sem escribir = 1; Int contadorLectores = 0; Escritor: wait(escribir); espera por escritor o lector Escritor_escribe; Escribe objeto signal(escribir); permite leer y/o escribir a otros, escritura completada Lector: wait(mutex); asegura acceso exclusivo a contador de lectores contadorLectores++; incrementa lectores if(contadorLectores == 1) then wait(escribir); Si es el primer lector espera si hay escritor signal(mutex); Lector_lee; wait(mutex); asegura acceso exclusivo a contador de lectores contadorLectores--; lector termin de leer if(contadorLectores == 0) then signal(escribir); no mas lectores por si escritor esperaba signal(mutex)
Notas sobre Lectores/Escritores
Primer lector se bloquea si hay un escritor activo cualquier otro escritor se bloquea tambin Si un escritor espera porque existen lectores activos, el ltimo lector lo despierta cuando sale pueden otros lectores entrar cuando el escritor est esperando? Cuando un escritor sale, si hay un escritor y un lector esperando quien entra?
Otro ejemplo clsico
Problema de Filsofos comensales
Cada filsofo tiene su plato de arroz, con 5 palitos 5 filsofos se sientan a la mesa. Piensan por un rato y cuando les da hambre comen Hay slo 5 palitos en la mesa (cada persona necesita 2 palitos para comer arroz a la manera china) Para poder comer cada filsofo tiene que obligatoriamente conseguir dos palitos
Problema es importante porque introduce posibles problemas de Deadlock(bloqueo mortal) y Starvation(inanicin)
Problema de Filsofos comensales
Problemas que pueden surgir con mala sincronizacin
Deadlock Hebras/Procesos estn en deadlock cuando
2 o ms hebras o procesos estn esperando por una condicin que slo puede ser causada por una hebra que tambien est esperando. Puede darse con 2 o ms hebras en la lista de espera de un mismo semforo?
Starvation o espera indefinida Hebras/Procesos esperan indefinidamente para poder accesar un recurso.
Ejemplo, una hebra en la lista de espera de un semforo de la cual estn entrando y saliendo continuamente hebras y la lista de espera de semforo es LIFO
Ejemplo deadlock con productor/consumidor
int contador = 0; //indica nmero de items en buffer char buffer[N]; int in = 0; int out = 0; sem mutex=1; sem vacio = N; sem lleno = 0; Productor while (true) { /* produce un item en proxProd */ wait(mutex); wait(vacio); buffer[in] = proxProd; in = (in + 1) % N; contador++; signal(mutex); signal(lleno); } Que sucede aqu? Consumidor While(true){ wait(lleno); wait(mutex); proxCons = buffer[out]; out = (out + 1) % N; contador--; signal(mutex); signal(vacio); /* consume proxCons */ }
Problemas con Semforos
A pesar que se pueden usar para resolver cualquier problema de sincronizacin Son variables globales por lo tanto pueden ser accesadas de cualquier hebra directamente
no es buena tcnica de ingeniera de software
No hay conexin entre el semforo y el recurso para el cual se quiere controlar acceso Usados como mutex (ingreso a seccin crtica) y para coordinacin (planificacin, eleccin quien tiene acceso al recurso) No se puede controlar su uso, no hay garanta que el programador los use adecuadamente (fcil de cometer errores)
Resumen
Semforos primitivas de sincronizacin de ms alto nivel que locks No relacin entre semforo y recurso que controla Fcil de cometer errores que pueden producir deadlock y starvation
Importante
entender bien problema antes de
utilizarlos
Prxima semana Monitores