Un semáforo es un tipo de datos abstracto que permite el uso de un recurso de manera exclusiva cuando varios procesos están compitiendo.
El tipo de datos abstracto cumple la siguiente semántica:
La operación wait() tiene que estár implementada como una instrucción atómica. Sin embargo, en muchas implementaciones la operación wait() puede ser interrumpida. Normalmente existe una forma de comprobar si la salida del wait() es debido a una interrupción o porque se ha dado acceso al semáforo.
La operación signal() también tiene que estár implementada como instrucción atómica. En algunás implementaciones es posible comprobar si se haya despertado un proceso con exito en caso que hubiera alguno bloqueado.
Para despertar los procesos existen varias formas que se destinguen en sus grados de justicia:
El acceso mutuo a regiones críticas se arregla con un semáforo que permita el acceso a un sólo proceso
S.init(1)
P1 P2
a: loop loop
b: S.wait() S.wait()
c: critical region critical region
d: S.signal() S.signal()
e: non-critical region non-critical region
f: endloop endloop
Observamos los siguiente detalles:
Si existen en un entorno solamente semáforos binarios, se puede simular un semáforo general usando dos semáforos binarios y un contador, p.e., con las variables delay, mutex y count.
La operación init() inicializa el contador al número máximo permitido. El semáforo mutex asegura acceso mutuamente exclusivo al contador. El semáforo delay atrapa a los procesos que superan el número máximo permitido.
La operación wait() se implementa de la siguiente manera:
delay.wait()
mutex.wait()
decrement count
if count greater 0 then delay.signal()
mutex.signal()
y la operación signal() se implementa de la siguiente manera:
mutex.wait()
increment count
if count equal 1 then delay.signal()
mutex.signal()
Unas principales desventajas de semáforos son: