P :: var x : integer; | Q :: var y : integer; |
s11; | s21; |
v := x; | y := v; |
s12; | s22; |
P :: var x : slot; | Q :: var y : slot; |
s11; | s21; |
write(x); | read(y); |
s12; | s22; |
P :: | Q :: |
s11; | s21; |
cr; | cr; |
s12; | s22; |
P :: | Q :: |
s11; | s21; |
cr1; | cr2; |
s12; | s22; |
Segment koda cr1 i cr2 sadrže ili zajedničke varijable ili pristup zajedničkom resursu (zajedničkom kodu) ili kombinaciju ova dva.
Zaključak: Ne sme se dozvoliti da dva procesa istovremeno pritupe zajedničkim varijablama / resursima (da uđu istovremeno u kritični region).
Kako obezbediti isključenje istovremenog pristupa kritičnom regionu ako precesi rade asinhrono i ako ne želimo da vodimo računa o brzini njihovog rada?
P :: | Q :: |
s11; | s21; |
Čekaj na signal iz Q; | Signaliziraj P da može da nastavi; |
s12; | s22; |
P :: | Q :: |
---|---|
|
|
gde je:
type slot = array 1 .. M of integer;
|
prostor bafera |
|
Operacija stavljanja podataka u bafer. |
|
Operacija uzimanja podataka iz bafera. |
Tehnika višestrukog bafera koristi se kod problema pristupa zajedničkoj memoriji i problema obaveštavanja.
|
prostor bafera |
|
ukazatelj kraja bafera |
|
brojac bafera |
|
Operacija stavljanja podataka u bafer. |
|
Operacija uzimanja podataka iz bafera. |
Proces P proizvodi podatke za proces Q. P ne sme da pošalje nove podatke u bafer sve dok Q ne uzme prethodne podatke iz bafera.
P čeka da Q “isprazni” bafer. Q čeka da P “napuni” bafer.
Q treba da obavesti P da je ispraznio bafer. P treba da obavesti Q da je napunio bafer.
Ovo je problem isključenja uzajamnog pristupa kombinovan sa problemom sinhronizacije.
P | |
|
zabrana prekida kritični region ukidanje zabrane prekida |
Q | |
|
Aplikacioni programer mora da pazi da kritične regione obavezno "opkoli" parom mašinskih naredbi DISABLE/ENABLE. |
1) Metod je neprihvatljiv u slučaju “dugih” kritičnih regiona (krajnje je opasno zabraniti prekide na duže vreme jer onemogućava multiprocesuiranje.)
2) Aplikacioni programer mora da se spušta na nizak jezički nivo (Assembler).
3) Metod nije dovoljan u slučaju višeprocesorskih sistema (zabrana prekida je na nivou jednog procesora.)
gde su:
P :: | Q :: |
---|---|
|
|
|
Ova funkcija predstavlja jednu mašinsku naredbu (koja ne može da se prekine) |
P :: | Q :: |
---|---|
|
|
U slučaju višeprocesorskog sistema (sa zajedničkom memorijom) potrebno je obezbediti isključivost istovremenog pristupa zajedničkoj memoriji. To se takođe postiže hardverski:
function testset(var l : boolean) : boolean;
begin
zabrana pristupa zajedničkoj memoriji; (MEMORY lock)
testset := l;
l := true;
dozvola pristupa zajedničkoj memoriji; (MEMORY unlock)
end;
4) Metod čekanja u petlji dovodi do bespotrebnog “traćenja” vremena procesora (procesor bi mogao da radio nešto korisnije dok se čeka na dozvolu pristupa).
5) Varijabla l je vidljiva u aplikacionom programu, to je opasno: opterećuje aplikacionog programera. Takođe važi nedostatak 2.
6) Metod ne zadovaoljava sistem sa prijemnicom (A -> R)(Running -> Ready): Neka P ima niži prioritet od Q i neka Q prekine P u trenutku dok se nalazi u kritičnom regionu, tada će Q beskonačno čekati u petlji, a P nikada neće moći da nastavi sa radom.
Zato treba kombinovati a) i b):
P :: | Q :: |
---|---|
|
|
Ipak ostaju nedostaci: 1), 2), 4) i 5).
Primitivni koncepti (1970-ih godina):
Strukurni koncepti (1980-ih godina):
Baza podataka:
Primitivne operacije:
Početno stanje:
Semantika primitivnih operacija:
ENTER ::
if busy then
{A -> B
R -> A}
else
busy := true;
EXIT ::
busy := false
if not empty(B) then
{ A -> R
B -> R
R -> A}
Primena:
P :: | Q :: |
---|---|
|
|
gde je:
Ovim su uklonjeni nedostaci 1) - 6).
Aplikacioni programer je dužan da:
(1968. G. Diijkstra “Cooperating Sequential Processes”)
Semafori su objekti operativnog sistema sa sledećim karakteristikama:
Baza podataka:
Primitivne operacije:
Početno stanje:
Semantika P i V operacija:
P :: | V :: |
---|---|
|
|
Ukoliko je N = 1, tj. se {0, 1} takav semafor je binarni semafor.
Primer kritičnog regiona
P :: | Q :: |
---|---|
|
|
gde je:
Primer signalizacije:
P :: | Q :: |
---|---|
|
|
Ako je proces P prvi počeo sa radom izvršiće naredbu s11 i preći će u blokirano stanje. Čekaće sve dok mu proces Q ne pošalje signal preko semafora sem.
Ovde se takođe koristi binarni semafor koji je inicijalizovan sa s = 0.
Primer primo-predaje preko jednostrukog bafera:
P :: | Q :: |
---|---|
|
|
gde su:
Svakom jednostrukom baferu treba, u operativnom sistemu, pridružiti po 2 binarna semafora za 2 uslova:
Primer primo-predaje preko konačnog bafera
P :: | Q :: |
---|---|
|
|
Svakom konačnom baferu treba, u operativnom sistemu, pridružiti 3 semafora:
Kada vrednost varijable space padne na 0 to znači da je bafer pun i da u njega ne može da se piše. Kada vrednost varijable count padne na 0 to znači da je bafer prazan i da iz njega ne može da se čita.
Inicijalizacija semafora:
Za domaći: Realizovati primo-predaju konačnog bafera samo pomoću binarnih semafora, s tim da se brojač punih mesta u baferu eksplicitno pojavi u aplikacionom programu.
(tehnika koja se koristi za sinhronizaciju i koordinaciju procesa u DEC-OS familiji (VMS OS) operativnih sistema)
Događaji su objekti operativnog sistema kojima se vrši:
Baza podataka:
Primitivne operacije:
Početno stanje:
Semantika primitivnih operacija:
WAITEVENT ::
if not eflg then
{
A -> B
R -> A
}
Ako nije nastupio događaj aktivan proces se stavlja u listu blokiranih procesa, a neki drugi proces koji je do tada bio u listi spremnih procesa se aktivira.
SETEVENT ::
eflg := true;
if not empty(B) then
{
A -> R
B -> R
R -> A
}
CLREVENT ::
eflg := false;
Primer primo-predaje preko jednostrukog bafera
Svakom jednostrukom baferu treba pridružiti po dva objekta tipa “događaj”:
P :: | Q :: |
---|---|
|
|
P može da pošalje u bafer podatke tek pošto svi prijemnici uzmu prethodni podatak iz bafera (B je jednostruki bafer).
P :: | Q :: |
---|---|
|
|
Ako jednostruki bafer ima n prijemnika potrebno je koristiti 2 x n objekta tipa “događaj”.
(Brinch-Hansen, Hoare, 1972.-1974.)
Uslovi su objekti operativnog sistema.
Baza podataka:
Primitivne operacije:
Početno stanje:
Semantika primitivnih operacija:
WAIT ::
{
A -> B
R -> A
}
SIGNAL ::
if not empty(B) then
{
A -> R
B -> R
R -> A
}
Za aplikativne programere ovo nije zgodan metod.
(Brinch-Hansen, 1972.-73., Hoare, 1974.)
Direktnom primenom regiona (Enter/Exit) i uslova (Wait/Signal) na konačni bafer dobija se sledeće rešenje za predajnik i prijemnik:
Rešenje 1.
P :: | Q :: |
---|---|
|
|
Deo koda u kome su vidljive varijable count, last i B predstavlja kritični region procesa P i Q. Oni se štite primitivama Enter i Exit.
Početne vrednosti:
Konačni bafer traži 3 objekta u operativnom sistemu:
Uslovi nonfull i nonempty su lokalni za kritični region.
Rešenje 1. nije ispravno!
Operacije WAIT(nonfull) i WAIT(nonempty) ne oslobađaju kritični region. Zato treba kombinovati operacije WAIT i EXIT.
Ako je proces blokiran na operaciji WAIT protrebno je osloboditi kritični region kako bi drugi procesi mogli da pristupe u kritični region i eventualno ostvare uslov na koji čeka prvi proces.
Ukoliko je SIGNAL zadnja operacija u kritičnom regionu, a neposredno ispred operacije EXIT, moguće je kombinovati SIGNAL i EXIT kao jednu jedinstvenu operaciju.
Ovakvo kombinovanje objekata predstavlja “ugnježdavanje” regiona i uslova.
Rešenje 2. Semantika modifikovanih primitivnih funkcija:
ENTER(r) ::
if busy then
{
A -> Br
R -> A
}
else busy := true;
WAIT(r, c) ::
{
A -> Bc
}
if not empty(Br) then
{
Br -> R
}
else busy := false;
{
R -> A
}
SIGNAL(r, c) ::
if not empty(Bc) then
{
Bc -> R
A -> R
R -> A
}
else if not empty(Br) then
{
Br -> R
A -> R
R -> A
}
else busy := false;
gde su:
P :: | Q :: |
---|---|
|
|
Nedostaci rešenja 2.:
Rešenje: Konačni bafer treba realizovati kao novi objekat operativnog sistema.
Baza podataka:
Primitivne operacije:
Početno stanje:
Semantika primitivnih operacija:
SEND(b, x) :: | RECEIVE(b, x) :: |
---|---|
Ako je bafer pun pozivni proces biće blokiran i čekaće sve dok se u baferu ne stvori mesto barem za jednu porciju podataka | Ako je bafer prazan pozivni proces biće blokiran i čekaće sve dok se u baferu ne pojavi barem jedna porcija podataka. |
Ovakav objekat zove se monitor (monitor tipa “konačni bafer”).
Monitor je objekat sa hijerarhijskom strukturom. Njemu su podređeni objekti tipa “uslov” i objekti tipa “region”. Aplikacioni programer od monitora vidi samo primitive SEND i RECEIVE.
Primo-predaja preko monitora tipa “konačni bafer”:
P :: | Q :: |
---|---|
|
|
Monitor je pasivni objekt koji objedinjuje u jednu jedinstvenu funkcionalnu celinu tri stvari:
Varijable monitora:
Procedure monitora:
Inicijalni kod:
Operativni sistem može u sebi da ima ugrađen određeni broj standardnih tipova monitora. Ukoliko to nije slučaj, tada monitore mora da definiše sam aplikacioni programer, kao i svaku drugu varijablu ili proceduru. Način definicije i deklaracije monitora zavisi od jezika na kome se piše aplikacioni program. Ovde će se koristiti notacija HOARE-a, koja je predložena po uzoru na klase O.J.DAHLA (jezik SIMULA).
|
Zaglavlje deklaracije monitora. |
|
Deklaracija varijabli monitora. |
|
Deklaracija procedura (funkcija) monitora. |
|
Inicijalni kod monitora. |
gde su:
Pozivi monitorove procedure iz procesa ili nekog drugog monitora (M.pk):
P :: | Q :: |
---|---|
|
|
Ista notacija se koristi za poziv primitiva WAIT i SIGNAL u okviru monitorovih procedura:
gde je C ime uslova.
Uslovi koji su lokalni za monitor takođe mogu da se tretiraju kao varijable monitora (varijable tipa “condition”) - var c : condition;
Predpostavljaće se da jezgro operativnog sistema u sebi sadrži objekte tipa uslov i region (tj. da operativni sistem podržava objekte tipa monitor).
monitor buffer;
begin
var B: array [0 .. N-1] of slot;
last : 0 .. N-1;
count : 0 .. N;
nonempty, nonfull : condition;
procedure SEND (x : slot);
begin
if count = N then nonfull.wait;
B [last] := x;
last := (last + 1) mod N;
count := count + 1;
nonempty.signal;
end;
procedure RECEIVE(var x : slot);
begin
if count = 0 then nonempty.wait;
x := B [(last - count) mod N];
count := count - 1;
nonfull.signal
end
begin
count := 0;
last := 0
end
end
monitor resource;
begin
var busy : boolean
nonbusy : condition;
procedure request;
begin
if busy then nonbusy.wait;
busy := true
end;
procedure release;
begin
busy := false;
nonbusy.signal
end
begin
busy := false;
end;
end
monitor allocator;
begin
var busy : array [1 .. N] of boolean;
nonempty : condition;
procedure request (var =: (0..N);
begin
i := first (busy);
if not i > 0 then nonempty.wait;
busy [i] := true
end;
procedure release (i : (0..N));
begin
busy [i] := false;
nonempty.signal
end
for j := 1 to N do busy [j] := false;
end
Ukoliko se razmenjuju veće količine podataka (datotetke za pseudo U/I, itd.) tada konačni bafer, postaje neracionalan. Treba omogućiti da predajnik i prijemnik istovremeno vrše prenos podataka.
Konačni bafer služi za prenos adrese podataka, a podaci se razmenjuju preko blokova iz POOL-a.
|
Traži i rezerviše blok. I nakon što napuni blok javlja procesu Q da je dobio podatke (tj. šalje mu adresu bloka u kome su podaci.) |
|
Uzima adresu bloka. I nakon što isprazni blok oslobađa prostor (vraća blok u POOL) |
Jedan alokator može da opslužuje veći broj primo-predajnih parova (information stream).
Da li FIFO strategija dodele prostora (objekat tipa uslov monitora A) zadovaoljava u slučaju da se brzine primo-predajnih parova znatno razlikuju?
Ovaj problem zahteva generalizaciju objekta tipa “uslov”: uvođenje priorioteta c.wait(p).
L letova. Svakom letu odgovara slog u datoteci letova. W1 , W2 , …, Wm su procesi koji ažuriraju slogove letova (WRITERS), a R1 , R2 , …, RM su procesi koji samo čitaju slogove letova (READERS).
Da bi se izbegla zbrka neophodno je uvesti kontrolu pristupa datoteci letova. Usvajaju se sledeća pravila:
Rešenje: Svakom slogu leta dodeljuje se po jedan monitor istog tipa sa 4 procedure:
Wi :: | Rj :: |
---|---|
|
|
Za ovaj problem potrebno je objekte tipa “uslov” proširiti sa još jednom primitvnom operacijom - c.empty, gde je:
monitor M;
begin
var r : integer; (Broj R koji citaju slog leta)
busy : boolean; (= true ako neki W azurira slog leta)
okr : condition; (uslov: R-ovi mogu da pristupe.)
okw : condition; (uslov: W-ovi mogu da pristupe.)
procedure startr;
begin
if busy or not okw.empty then okr.wait;
r := r + 1;
okr.signal (Ako jedan R pocne mogu i svi ostali)
end;
procedure endr;
begin
r := r - 1;
if not r > 0 then okw.signal;
end;
procedure startw;
begin
if r > 0 or busy then okw.wait;
busy := true;
end;
procedure endw;
begin
busy := false;
if not okr.empty then okr.signal;
else okw.signal;
end;
r := 0;
busy := false;
end;