Semáforos Lecturas: Ben-Ari, secciones 4.1, 4.2, 4.3, 4.6 Andrews, intro. cap. 4 y sección 4.1 Manuel Carro Universidad Politécnica de Madrid Este texto se distribuye bajo los términos de la Creative Commons License M. Carro (UPM) Semáforos 1 / 20 Definición Semáforos Definición Tipo abstracto de datos (Dijkstra) Especificación de comportamiento: sem ∈ N Init(sem, n) Wait(sem) Signal(sem) ≡ h sem := n i ≡ h AWAIT sem > 0 → sem := sem - 1 i ≡ h sem := sem + 1 i Código entre h· · · i: acción atómica Init(sem, n): sólo inicialización valores AWAIT Cond suspende tarea hasta cumplimiento de Cond Wait(sem): suspende hasta que sem > 0, entonces decrementa Signal(sem): incrementa sem M. Carro (UPM) Semáforos 2 / 20 Definición Exclusión mutua con semáforos X := ...; −−Compartida Init (Mutex , 1); −−Nadie en sección crı́tica Wait ( Mutex ) ; −− S .C . X := X + X; S i g n a l ( Mutex ) ; Invariante: Mutex = 0 ↔ algún proceso en sección crı́tica Wait: Puede decrementar si sección crı́tica está libre Suspende en otro caso Signal: Siempre puede incrementar Puede rearrancar alguna tarea suspendida M. Carro (UPM) Semáforos 3 / 20 Definición Semáforos Clases e implementación Binarios (sem ∈ {0, 1}): exclusión mutua Generales (sem ∈ N ): sincronización más avanzada Semáforos binarios: Signal cuando ya tiene un valor 1 → efecto indefinido No son parte nativa de Ada Implementación (entre los ejemplos de la asignatura) como packages: Bin Semaphore : binario Semaphore : generales Definen tipo paramétrico (para inicializar semáforo) M. Carro (UPM) Semáforos 4 / 20 Un interfaz de semáforos Semáforos en Ada Sólo diferencias sintácticas con el esquema ya visto: −− V a r i a b l e compartida X : Natural : = 1 ; −− Sem áforo b i n a r i o i n i c i a l i z a d o a 1 Mutex : Bin Semaphore . Semaphore Type ( 1 ) ; task type Add ; task body Add i s begin Mutex . Wait ; −− Entrada en s e c c i ó n c r ı́ t i c a X := X + X; −− Secci ón c r ı́ t i c a Mutex . S i g n a l ; −− S a l i d a de s e c c i ó n c r ı́ t i c a end Add ; M. Carro (UPM) Semáforos 5 / 20 Un interfaz de semáforos Semáforos en Ada Cuestiones sintácticas Inicialización explı́cita en declaración de variable: Mutex: Bin Semaphore.Semaphore Type(1); Notación de objetos: M. Carro (UPM) Procedimientos Objetos Wait(Mutex) Mutex.Wait Signal(Mutex) Mutex.Signal Semáforos 6 / 20 Usando semáforos Control de aparcamiento Semáforos generales: sincronización Binarios: exclusión mutua (ya sabı́amos hacerla) Generales: misma definición (excepto que sem ∈ N ), más potencia Ejemplo: aparcamiento 1 entrada / 1 salida Barreras / detectores de entrada y salida Permitir entrar coches (si hay sitio) Descontar los que vayan saliendo M. Carro (UPM) Semáforos Usando semáforos 7 / 20 Control de aparcamiento Operaciones externas, procesos, recursos Aparcamiento Barrera_Entrada Barrera_Salida Proceso Entrada Entrar Abrir_Entrada Salir Estado Aparcamiento Proceso Salida Abrir_Salida procedure Barrera Entrada: detecta coche a la entrada; bloqueante procedure Abrir Entrada: abre la barrera de entrada procedure Barrera Salida: detecta coche a la salida; bloqueante procedure Abrir Salida: abre barrera saluda Estado Aparcamiento: depende de la implementación M. Carro (UPM) Semáforos Usando semáforos 8 / 20 Control de aparcamiento Aparcamiento: solución 0 loop −− Entrada Espacio : = False ; Barrera Entrada ; while not Espacio loop i f N C < Max then N C := N C + 1; Espacio : = True ; end i f ; end loop ; Abrir Entrada ; end loop ; N C : Tipo Tam : = 0 ; loop −− S a l i d a Barrera Salida ; N C : = N C − 1; Abrir Salida ; end loop ; M. Carro (UPM) Semáforos 9 / 20 Usando semáforos Control de aparcamiento Aparcamiento: solución 1 Con un semáforo binario loop −− Tarea e n t r a d a Barrera Entrada ; Espacio : = False ; while not Espacio loop Mutex . Wait ; i f N C < Max then N C := N C + 1; Espacio : = True ; end i f ; Mutex . S i g n a l ; end loop ; AbrirE ; end loop ; Mutex : Semaphore Type ( 1 ) ; N C : Tipo Tam : = 0 ; loop −− Tarea s a l i d a Barrera Salida ; Mutex . Wait ; N C : = N C − 1; Mutex . S i g n a l ; Abrir Salida ; end loop ; M. Carro (UPM) Semáforos Usando semáforos Solución 1: protección de 10 / 20 Control de aparcamiento NC Recurso compartido: número coches aparcados while not Espacio loop Mutex . Wait ; i f N C < Max then N C := N C + 1; Espacio : = True ; end i f ; Mutex . S i g n a l ; end loop ; −− Hay espacio Acceso en exclusión mutua Pero: aparcamiento lleno −→ espera activa ¿Llevar mutex fuera de bucle principal? ¿Encapsular sólo N C := N C + 1? ¿No encapsular Espacio := True? M. Carro (UPM) Semáforos Usando semáforos 11 / 20 Control de aparcamiento Solución 2 Mutex , No Lleno : Semaphore Type ( 1 ) ; N C : Tipo Tam : = 0 ; loop −− S a l i d a Barrera Salida ; Mutex . Wait ; N C : = N C − 1; i f N C = MAX − 1 then No Lleno . S i g n a l ; end i f ; Mutex . S i g n a l ; Abrir Salida ; end loop ; M. Carro (UPM) loop −− Entrada Barrera Entrada ; No Lleno . Wait ; Mutex . Wait ; N C := N C + 1; i f N C < Max then No Lleno . S i g n a l ; end i f ; Mutex . S i g n a l ; Abrir Entrada ; end loop ; Semáforos 12 / 20 Usando semáforos Control de aparcamiento Solución 2: fuego cruzado Mutex: protege sección crı́tica No Lleno: sincroniza (sincronización condicional) No Lleno = 0 ←→ N C = MAX (−→ bloqueo si aparcamiento lleno) No Lleno = 0 sii ha entrado el último coche No obvio — pero no hace espera activa ¿Intercambiar No Lleno.Wait y Mutex.Wait? M. Carro (UPM) Semáforos Usando semáforos 13 / 20 Control de aparcamiento Solución 3 Huecos : Semaphore . Semaphore Type ( Max ) ; loop −− S a l i d a Barrera Salida ; Huecos . S i g n a l ; Abrir Salida ; end loop ; loop −− Entrada Barrera Entrada ; Huecos . Wait ; Abrir Entrada ; end loop ; Huecos.Wait permite paso si hay espacio Huecos.Signal libera espacio ¿El poder de los semáforos? Codificar con Peterson Repetir análisis suponiendo que hay dos (o más) entradas M. Carro (UPM) Semáforos Usando semáforos 14 / 20 Buffer acotado Buffer acotado Cola acotada Procesos leen y escriben Productor Consumidor Buffer lleno: productor espera Buffer vacı́o: consumidor espera Buffer Proceso Productor Poner(Item) Tomar(Item) Proceso Consumidor Estado Buffer M. Carro (UPM) Semáforos 15 / 20 Usando semáforos Buffer acotado Solución 1: sólo exclusión mutua Mutex : Bin Semaphore ( 1 ) ; Buffer : Tipo Buffer ; loop P r o d u c i r ( Un Dato ) ; Mutex . Wait ; << I n s e r t a en b u f f e r >> Mutex . S i g n a l ; end loop ; loop Mutex . Wait ; << Q u i t a de b u f f e r >> Mutex . S i g n a l ; U t i l i z a r ( Un Dato ) ; end loop ; Precondiciones secuenciales vs. Precondiciones concurrencia M. Carro (UPM) Semáforos Usando semáforos 16 / 20 Buffer acotado Solucion 2 Mutex : Buffer : Vacios : Llenos : Semáforos con dos misiones diferentes Bin Semaphore ( 1 ) ; Tipo Buffer ; Semaphore ( Max ) ; Semaphore ( 0 ) ; Esencialmente, aparcamiento simétrico Pero: estructura de datos separada de semáforo loop −− P r o d u c t o r P r o d u c i r ( Un Dato ) ; Vacios . Wait ; Mutex . Wait ; <<I n s e r t a en b u f f e r >> Mutex . S i g n a l ; Llenos . S i g n a l ; end loop ; M. Carro (UPM) loop −− Consumidor Llenos . Wait Mutex . Wait ; <<Q u i t a de b u f f e r >> Mutex . S i g n a l ; Vacios . S i g n a l Consumir ( Un Dato ) ; end loop ; Semáforos Usando semáforos 17 / 20 Buffer acotado Buffer de un dato Dato : Tipo Dato ; Lleno : Bin Semaphore ( 0 ) ; Vacio : Bin Semaphore ( 1 ) ; loop −− P r o d u c t o r P r o d u c i r ( Un Dato ) ; Vacio . Wait ; Dato : = Un Dato ; Lleno . S i g n a l ; end loop ; loop −− Consumidor Lleno . Wait Este Dato : = Dato ; Vacio . S i g n a l ; Consumir ( Este Dato ) ; end loop ; Establecer invariantes ¿Por qué es más simple que el buffer general? M. Carro (UPM) Semáforos 18 / 20 Ventajas e inconvenientes Semáforos desde la lejanı́a Algo truculentos y de bajo nivel Pero ampliamente disponibles (POSIX, API Win32) Sincronización condicional ad-hoc Linealización siempre posible, pero a veces no clara Mezclada con exclusión mutua Para implementar abstracciones de nivel superior M. Carro (UPM) Semáforos 19 / 20 Ventajas e inconvenientes Ejercicio: buffer par/impar Productor de números pares e impares (en cualquier orden) Consumidores: I I Uno necesita números pares Otro necesita números impares Buffer Proceso Productor Consumidor Pares Tomar_Par(Item) Poner(Item) Tomar_Impar(Item) Estado Buffer Consumidor Impares Usar un buffer de un dato M. Carro (UPM) Semáforos 20 / 20