Za reševanje problemov sinhronizacije sočasnih procesov je Dijkstra
uvedel koncept semaforjev in takoimenovanih operacij P
in V. Oznake teh operacij izhajajo
iz holandskih besedic vhod in izhod. Semafor je ščitena spremenljivka
(pravzaprav podatkovna struktura), ki jo lahko inicializiramo ter doseľemo
le z operacijami P in V. Binarni semaforji
lahko zavzamejo le vrednosti 0 in 1, Števni semaforji
pa poljubne nenegativne vrednosti.
Operacijo P na semaforju S zapiąemo kot P(S) in deluje tako:
if S>0 then S:= S-1 else (* pocakaj na S v ustrezni vrsti *);Operacijo V na semaforju S pa zapiąemo kot V(S) in deluje tako
if (* eden ali vec procesov caka v vrsti na S *) then (* naj vstopi en proces *) else S:=S+1;Procesi naj čakajo na zaključek P(S) v čakalni vrsti tipa FIFO (first in - first out). Zato je vsak semafor podatkovna struktura, ki vsebuje en integer in eno vrsto.
V literaturi označujejo operaciji P(S) in V(S) tudi z imeni wait(semaphore) in signal(semaphore), ki imata v bistvu enak pomen.
Operaciji P in V morata biti nedeljivi. Same konkretne implementacije semaforjev so lahko različne. Če imamo na voljo instrukcije tipa test-and-set, jih uporabimo, sicer pa ne dovolimo prekinitev (disable interrupts) med samim izvajanjem operacij wait in signal.
Demonstracija semaforjev Java
in semaforji
program sinhronizacija; var dogodek:semaphore; procedure process_A; begin (*..predhodne operacije...*) wait(dogodek); (* proces_A caka na dogodek v procesu B *) (*...nadaljevanje procesa...*) end; procedure process_B; begin (*...predhodne operacije ..*) signal(dogodek); (*..nadaljevanje procesa..*) end; begin initSemaphore(dogodek,0); parbegin process_A; process_B; parend; end.
Primer: Speči brivec
program proizvajalec_porabnik; var zasedeno:semaphore; vpisano:semaphore; buffer: integer; procedure proizvajalec; var rezultat: integer; begin repeat racunaj(rezultat); wait(zasedeno); (* vstop v kriticno sekcijo *) buffer:=rezultat; signal(vpisano); (* sinhronizacija *) signal(zasedeno); (* sprostitev kriticne sekcije *) until FALSE; end; procedure porabnik; var podatek:integer; begin repeat wait(vpisano); (* blokiran proces, ce podatka se ni *) wait(zasedeno); (* vstop v kriticno sekcijo *) podatek:=buffer; signal(zasedeno); (* sprostitev kriticne sekcije *) izpis(podatek); until FALSE; end; begin initSemaphore(zasedeno,1); initSemaphore(vpisano,0); parbegin proizvajalec; porabnik; parend; end.
Semaforji so zelo primitivni in z njimi težko izrazimo zelo kompleksne konkurenčne probleme. Tako si težko zapomnimo, kateri ščiteni strukturi smo priredili dani semafor. Mimogrede pozabimo uporabiti kakšno instrukcijo wait in prezgodaj vstopimo v kritično sekcijo. Procesi lahko tudi ostanejo neomejeno blokirani, ker (morda zaman) čakajo na odrešilno operacijo signal, ki bi jo moral uporabiti nek drug proces.
Ali Java
pozna semaforje
Primeri s semaforji
v Javi
Primer števnega
semaforja