Professional Documents
Culture Documents
Uvod U Operativne Sisteme
Uvod U Operativne Sisteme
SINHRONIZACIJA
PROCESA
I
MEĐUPROCESNA
KOMUNIKACIJA
9.3.2016 1
NADMETANJE ZA RESURSE
9.3.2016 2
Primjer: Korektno punjenje
bafera
9.3.2016 3
Primjer: Natjecanje
9.3.2016 4
BACI
BACI je akronim Ben-Ari Concurrent Lista procesa koji se konkurentno
Interpreter. U pitanju je programski jezik izvršavaju uokvirena je u cobegin blok.
baziran na Pascalu ili C-u, sa svrhom Takvi blokovi se ne mogu gnijezditi i
upoznavanja konkurentog programiranja, moraju se nalaziti u glavnom programu.
koje se javlja u problemima multitaskinga, PCODE naredbe koje pripadaju
raĉunarskih mreža i paralelnog nabrojanim procedurama se prepliću
programiranja. interpreterom u sluĉajnom redoslijedu,
tako da višestruko izvršavanje istog
programa koji ima cobegin blok će
BACI C-- je podskup jezika C++. Dakle, izgledati nedeterministiĉko. Glavni
prati se C/C++ sintaksa uz neka program se zaustavlja dok se svi procesi
ograniĉenja i nove tipove. u cobegin bloku ne zaustave, nakon ĉega
glavni program nastavlja izvršavanje
naredbi iza bloka. Na primjer:
cobegin {
proc1( ... ); proc2( ... ); ... ; procN( ... );
}
9.3.2016 5
BACI-UPOTREBA
BACI izvorna datoteka ukoliko
2. Izvršiti dobijenu .pco datoteku
se koristi C— kompajler treba
Upotreba:
koristiti .cm suffix. Za izvršenje bainterp [opcionalne_komande] ime_pco_datoteke
programa u BACI, postoje dva Opcionalne_komande:
koraka: -d startaj debager, sa izvršavanjem korak po korak i
1. Prevesti ".cm" datoteku da se prekidnim taĉkama
dobije PCODE datoteka (.pco) -e prikaži activation record (AR) pri ulasku u svaki
proces
Upotreba:
-x prikaži activation record (AR) pri izlasku iz svakog
bacc [opcionalne_komande] procesa
izvorna_datoteka -t Najavi kraj procesa
Opcionalne_komande: -h prikaži help
-h prikazi help -p prikaži PCODE instrukcije kako se izvršavaju
Proces {
while (true) {
ULAZAK U KRITIĈNU SEKCIJU
Pristup djeljenim var.; // Kritiĉna Sekcija;
IZLAZ IZ KRITIĈNE SEKCIJE
Izvršava druge poslove
}
}
9.3.2016 9
SINHRONIZACIJA S
ZAPOSLENIM ĈEKANJEM
Moguća rješenja
Zabraniti prekida
Djeljena varijabla
Peterson‘o rješenje
Instrukcija TSL
9.3.2016 10
ZABRANA PREKIDA
Zabraniti sve prekida odmah po ulasku u kritiĉnu sekciju i omogućiti ih prije napuštanje
kritiĉne sekcije.
Zašto se ovo radi?
Sa zabranjenim prekidima, ne može se desiti prekid od sata. (Izmjena procesa na
procesoru se vrši samo kao rezultat prekida sata ili druge vreste prekida, a sa
zabranjenim prekidima izmjena se ne može desiti)
Problemi:
Kako ovo radi?
Šta ako proces zaboravi da omogući prekide?
Multiprocessor? (zabrana prekida ima efekta samo na jedan procesor)
Koristi se samo unutar OS
Disable_interrupt();
<<< Kritiĉna sekcija >>>
Enable_interrupt();
9.3.2016 11
BACI ATOMIĈKE FUNKCIJE
Ovo je BACI ekvivalent iskljuĉenju
atomic void HelloA () {
cout << "Hello from A" <<endl; interapta
}
atomic void HelloB () { Funkcija je atomiĉka ako je ništa ne
cout << "Hello from B" <<endl; prekida, nema izmjene konteksta
}
atomic void HelloC () { Ako je kritiĉna sekcija samo dio
cout << "Hello from C" <<endl; funkcije nisu optimalno rješenje
}
main () {
cobegin {
HelloA();
HelloB();
HelloC();
}
}
9.3.2016 12
DIJELJENA VARIJABLA
Kada proces ulazi u kritiĉnu sekciju prvo testira varijablu
Ako je varijabla jednaka 0, proces je postavi na 1 i ulazi u
kritiĉnu sekciju
Dakle, 0 znaĉi da nema procesa u kritiĉnoj sekciji a jedna znaĉi
da ga ima
Postoji problem:
Ako proces 1 vidi da je djeljena varijabla jednaka 0 pa
doĊe do izmjene procesa, tada Proces 2 takoĊe vidi da je
djeljena varijabla jednaka 0 i postavlja je na 1 i ulazi u
kritiĉnu sekciju
Kada proces 1 nastavi svoje izvršavanje, on ―zna‖ da je
varijabla jednaka 0 i postavlja je na 1 i oba procesa ulaze u
9.3.2016
kritiĉnu sekciju koda 13
STRIKTNA IZMJENA
while (TRUE) { while (TRUE) {
while(turn != 0); /* petlja * / while(turn != 1); /* petlja * /
kritiĉna_sekcija (); kritiĉna_sekcija ();
turn = 1; turn = 0;
kod_izvan_kritiĉne_sekcije(); kod_izvan_kritiĉne_sekcije();
} }
a) Proces 0 b) Proces 1
zaposleno ĉekanje
proces blokiran sa onim procesom koji nije u njegovoj kritiĉnoj sekciji
nije ozbiljan kandidat za rješenje problema meĊusobnog iskljuĉivanja
9.3.2016 14
PETERSONOV ALGORITAM
#define TRUE 1 Zadovoljava
#define N 2 /* broj procesa */ sve uslove
int turn; /* ĉiji je redosljed? */ rješenja
int interested[N]; /* sve vrijednosti inicijalno na 0 (FALSE)*/ kritiĉne
void ulazak_u_sekciju(int process) /* proces je 0 ili 1 */{ sekcije ako
int other; /* broj drugog procesa */
other = 1 – process; /* prvi proces */
je
interested[process] = TRUE; /* interes za ulazak u k.s. */ dodjeljivanje
turn = process; /* postavi zastavicu */ vrijednosti
while (turn == process && interested[other] == TRUE) ; varijablama
} atomski
void izlazak_iz_sekcije(int process)
/* proces: koji napušta kritiĉnu sekciju */ {
interested[process] = FALSE;
/* ukazuje na izlazak iz kritiĉne sekcije*/
}
9.3.2016 15
INSTRUKCIJA TSL
TSL (<mem loc>) { Mašinsku instrukciju
if (<memloc> == 0) { interapt ne prekida
<mem loc > = 1;
Semantika dana u
return 0;
pseudokodu s lijeve
}
strane
else {
return 1; Na Intel procesorima
} BTS EAX,3
}
Treći bit registra EAX
stavi u Carry i postavi
ga na 1
9.3.2016 16
ZAŠTITA KRITIĈNE SEKCIJE
INSTRUKCIJOM TSL
ulazak_u_kritiĉnu_sekciju:
TSL REGISTER,LOCK | kopiraj LOCK u registar i LOCK na 1
CMP REGISTER,#0 | da li je LOCK bio nula?
JNE ulazak_u_kriticnu_sekciju | ako nije bio nula, LOCK je bio
| postavljen dakle vrti se u petlji
RET | vrati se pozivaocu; ulazak u kritiĉnu sekciju
izlazak_iz_kritiĉne_sekcije:
MOVE LOCK,#0 | smjesti 0 u varijablu LOCK
RET | vrati se pozivaocu
9.3.2016 17
BACI TEST AND SET
ILUSTRACIJA
atomic int test_and_set(int& target) { Unesite, prevedite i pokrenite ovaj
int u;
u = target;
program nekoliko puta. Svako
target = 1; izvršavanje je razliĉito.
return u;
}
int lock = 0; TestAndSet je najprimitivnija
void proc(int id) {
int i = 0; potrebna mašinska instrukcija za
int j; realizaciju konkurentnosti. Ona daje
while(i < 10) {
while (test_and_set(lock)) /* wait */ ; kao rezultat prethodnu vrijednost
for (j=1;j<=50;j++) cout << id;
lock = 0;
memorijske lokacije i postavlja je na
i++;
}
} Pazite na tackazarez iza naredbe
main() { while (test_and_set(lock)) /* wait */ ;
cobegin {
proc(1); proc(2); proc(3); Ukidanjem ove while petlje, procesi
} se razmjenjuju prilikom ispisa na
}
ekran
9.3.2016 18
SEMAFORI
Semafor varijabla predstavlja nenegativnu
varijablu - broj apstraknih resursa.
Nova varijabla ima 2 operacije
Operacija P(), Wait() ili Down() se koristi da bi
se dobio resurs i dekrementrira se broj
Operacija V(), Signal ili Up() se koristi da
oslobodi resurs i inkrementira broj.
Bilo koja semaforska operacija jenedjeljiva
(atomska)
9.3.2016 19
OPERACIJE NAD
SEMAFORIMA
P(sem)/* proberen – testiraj, operacija wait(sem) */{
while (sem <= 0);
sem = sem – 1;
}
V(sem) /* verhogen – inkrementiraj, opeacija signal(sem) */
{
sem = sem + 1;
}
9.3.2016 20
OPERACIJE NAD
SEMAFORIMA
p(csem) {
while (1) {
ulazak u k.s.;
if (csem.value <= 0) {
izlazak_iz_k.s.;
continue;
}
else {
csem.value = csem.value – 1;
izlazak_iz_k.s.;
break;
}
}
}
v(csem) {
ulazak u k.s.;
csem.value = csem.value + 1;
izlazak_iz_k.s.;
}
9.3.2016 21
MUTEX ILI BINARNI SEMAFOR
Varijabla samo sa dva stanja
zakljuĉani
otkljuĉano
Pojednostavljena verzija semafora
Mutex se koristi za meĊusobno iskljuĉivanje
9.3.2016 22
SEMAFORI S BLOKIRANJEM
Problem sa prethodnim rješenjima
Zaposleno ĉekanje
Trošenje CPU-a
Prioritetna inverzija:
kritiĉnu sekciju
Procesi nižeg prioriteta mogu da se nikad ne izvrše pošto oni sa
kritiĉnu sekciju
Operacije nad semaforima izvršavaju operacije ―spavanje‖ i
―buĊenje‖
9.3.2016 23
SEMAFOR S BLOKIRANJEM
PROCESA
struct csem { p(sem) {
int value; while (1) {
acquire_mutex (csem.mutex); ulazak u k.s.
processlist * queue; if (csem.value <= 0) {
Csem * mutex; Insert_queue (getpid(), csem.queue);
} Release_mutex_and_block (csem.mutex); /* atomski
*/
}
else {
csem.value = csem.value – 1;
Release_mutex (csem.mutex); // izlazak iz kritiĉne
sekcije
Break;
}
}
}
v(csem) {
acquire_mutex (csem.mutex); // ulazak u k.s.
csem.value = csem.value + 1;
dequeue_and_wakeup (csem.queue);
// prevoĊenje procesa iz stanja
// blokiranosti u red spremnih procesa
Release_mutex (csem.mutex); // izlazak iz k.s.
}
9.3.2016 24
KOJU VRSTU SEMAFORA
KORISTITI
Zaposleno ĉekanje (spinlock)
– Troši cikluse procesora
Sleep&Wakeup (zakljuĉavanje blokiranjem)
– Interni rad kod izmjene konteksta
Hybrid konkurentno rješenje (spin-block)
– Primjeni zaposleno ĉekanje ako je vrijeme
ĉekanja kraće od vremena izmjene konteksta
– Koristi sleep & wakeup ako je vrijeme ĉekanja
duže od vremena izmjene konteksta
9.3.2016 25
BACI SEMAFORI
semaphore je predefinisana vrijednost u BACI. On je nenegativna
varijabla kojoj se može pristupiti samo na ograniĉen naĉin. BACI takoĊer
ima podtip binarysem koji je binarni semafor koji samo predpostavlja
vrijednosti 0 i 1. Semaforske funkcije ukljuĉuju:
initialsem ( semaphore, integer_expression ): Inicijalizira semafor na
navedenu vrijednost.
p ( semaphore) ili wait (semaphore): Ako je semaphore > 0 umanji
semafor za 1 i vrati se, ĉime pozivalac može nastaviti izvršenje. Ako je
semaphore = 0, pozivalac se prebacuje u ĉekanje.
v ( semaphore) ili signal (semaphore): Ako je semaphore = 0 i jedan ili
više procesa ĉekaju na semafor, sluĉajno probudi jedan od ĉekajućih
procesa. Ako ni jedan proces ne ĉeka na semafor, uvećaj semafor za
jedan. U svakom sluĉaju, pozivalac nastavlja s izvršenjem.
9.3.2016 26
UZAJAMNO ISKLJUĈIVANJE
SEMAFORIMA
semaphore mut;
void HelloA () {
wait(mut); Svako izvršavanje je razliĉito. Ali,
cout << "Hello from A" <<endl; više nema prekidanja ured
signal(mut); ispisa. Semafori su realizovali
}
void HelloB () { uzajamno iskljuĉivanje. Semafor
wait(mut); je inicijaliziran na 1. Krene li
cout << "Hello from B" <<endl;
signal(mut);
izvršenje bilo koje procedure,
} pokrene se wait. On umanji
void HelloC () { semafor na 0 i sprjeĉava da
wait(mut);
cout << "Hello from C" <<endl; wait nad istim semaforom
signal(mut); nastavi izvršavanje. Tek kada je
} tekst ispisan, naredba signal
main () {
initialsem(mut,1); inkrementira semafor za jedan i
cobegin { time se može nastaviti
HelloA(); HelloB(); HelloC();
}
izvršavanje zaustavljenih rutina
} u wait..
9.3.2016 27
SEMAFORI ZA LIMITIRANJE
BROJA PROCESA
semaphore limit; void HelloC() { void HelloE () {
void HelloA () { int i,j; int i,j;
int i,j; wait(limit); wait(limit);
wait(limit); for (i=1;i<=5; i++) { for (i=1;i<=5; i++) {
for (i=1;i<=5; i++) { for (j=1;j<=5; j++) cout << "C"; for (j=1;j<=5; j++) cout << "E";
for (j=1;j<=5; j++) cout << "A"; cout << endl; cout << endl;
cout << endl; } }
} signal(limit); signal(limit);
signal(limit); } }
}
void HelloD () {
void HelloB () { int i,j; main () {
int i,j; wait(limit); initialsem(limit,2);
wait(limit); for (i=1;i<=5; i++) { cobegin {
for (i=1;i<=5; i++) { for (j=1;j<=5; j++) cout << "D"; HelloA();
for (j=1;j<=5; j++) cout << "B"; cout << endl; HelloB();
cout << endl; } HelloC();
} signal(limit); HelloD();
signal(limit); } HelloE();
} }
Od pet procesa, dva se izvršavaju }
istovremeno, što je postignuto
9.3.2016 inicijalizacijom semafora na 2 28
UPOTREBA SEMAFORA ZA
REDOSLIJED IZVRŠAVANJA
semaphore enda,endb,mut;
void HelloA () { Semafori enda i endb
cout << "Hello from A" <<endl;
signal(enda);
postavljeni na 0, te
} podprogram HelloC ĉeka da
void HelloB () {
cout << "Hello from B" <<endl;
se završe i HelloA i HelloB.
signal(endb); Tako se HelloC uvijek
}
void HelloC () { izvršava posljednji.
wait(enda);
wait(endb);
cout << "Hello from C" <<endl;
}
main () {
initialsem(enda,0);
initialsem(endb,0);
cobegin {
HelloA();
HelloB();
HelloC();
}
}
9.3.2016 29
WINDOWS API ZA
SINHRONIZACIJU
InitializeCriticalSectionAndSpinCount(
lpCriticalSection, dwSpinCount) CreateMutex(lpMutexAttributes,bInitialOwner
Inicijalizira kritiĉnu sekciju i brojaĉ , lpName)
pokušaja ulaska
Kreira objekt uzajamnog iskljuĉenja
EnterCriticalSection(lpCriticalSection)
Ĉeka na ulaz u kritiĉnu sekciju i uĊe OpenMutex( dwDesiredAccess,
kada je slobodna bInheritHandle,lpName)
TryEnterCriticalSection( lpCriticalSection) Otvara postojeći Mutex
Pokušava ući u kritiĉnu sekciju bez CloseHandle(hObject)
ĉekanja Zatvara sinhronizacijski objekt
LeaveCriticalSection(lpCriticalSection) CreateEvent( lpEventAttributes,
Otkljuĉava kritiĉnu sekciju bManualReset,bInitialState,lpName)
DeleteCriticalSection(lpCriticalSection)
Kreira ili otvara objekt dogaĊaja
Briše kritiĉnu sekciju
CreateSemaphore(lpSemaphoreAttributes,
WaitForSingleObject(hHandle,dwMilliseconds)
lInitialCount,lMaximumCount,lpName)
Ĉeka na oslobaĊanje sinhronizacijskog
objekta ii navedeno vrijeme Kreira semafor
WaitForMultipleObjects(nCount,lpHandles, ReleaseSemaphore( hSemaphore,
bWaitAll,dwMilliseconds) lReleaseCount,lpPreviousCount)
Ĉeka na oslobaĊanje bar jednog ili svih Uvećava vrijednost semafora
sinhronizacijskih objekata
9.3.2016 30
POSIX API ZA
SINHRONIZACIJU
sem_open(pcName,iOflag,iNmode,iValue)Povezuje se ili kreira imenovani
semafor
sem_init(pSem,iPshared,iValue) Inicijalizira neimenovani semafor
sem_close(pSem) Završava vezu s otvorenim semaforom
sem_unlink(pcName) Završava vezu s otvorenim semaforom i uklanja ga
kada ga zadnji proces prestane koristiti
sem_destroy(pSem) Uklanja semaforsku strukturu neimenovanog
semafora
sem_getvalue(pSem,pValue) Kopira vrijednost semafora u cijeli broj
sem_wait(pSem), sem_trywait(pSem) Blokira se kada semafor drži drugi
proces ili vraća grešku
sem_post(pSem) Povećava brojaĉ semafora
9.3.2016 31
MONITORI
Hoare 1974
Abstraktni tip podataka za rad/definisanje djeljenih resursa
Sastoji se od:
– Djeljenih lokalnih podataka
• Predstavljaju resurse
• Ne može im se pristupiti izvana
– Procedura koje rade nad podacima
• Sredstvo za pristup resursima
• Mogu raditi nad lokalnim podacima u monitoru
– Sinhronizacionih elemenata
• MeĊu thread-ima koji pristupaju procedurama
9.3.2016 32
STRUKTURA MONITORA
Monitor monitor_name { Monitor stack {
// shared variable declarations int top;
procedure P1(. . . .) { void push(any_t *) {
.... ....
} }
procedure P2(. . . .) { any_t * pop() {
.... ....
} }
procedure PN(. . . .) { initialization_code() {
.... ....
} }
initialization_code(. . . .) { }
.... Samo jedan primjerak steka
} može biti modifikovan u jednom
} trenutku
9.3.2016 33
KARAKTERISTIKE MONITORA
Internoj implementaciji tipa monitora ne može se pristupiti direktno iz
raznih thread-a.
Enkapsulacija obezbjeĊena kod tipa monitor -ograniĉava pristup na
lokalne varijable samo kroz lokalne procedure.
Razlike u odnosu na c++clase/objekte
– Konstukcija monitor ne dozvolja konkurentan pristup svim
procedurama definisanim u monitoru.
– Samo jedan thread/proces može biti aktivan u monitoru u
jednom trenutku.
Monitor je konstrukcija podržana od programskih jezika dok
semafori i mutexi traže hardversku podršku
9.3.2016 34
KARAKTERISTIKE MONITORA
Monitori garantuju meĊusobno
iskljuĉivanje
Samo jedan thread može izvršiti
proceduru u monitoru u bilo koje
vrijeme
Ako drugi thread pozove proceduru
u monitoru u isto vrijeme
Biće blokiran i ĉekati dok ne uĊe
u monitor
⇒ Potrebno je formirati red
ĉekanja za thread-ove
Ako se thread koji se izvršava u
monitoru blokira, drugi thread može
ući u monitor
9.3.2016 35
MONITOR U BACI
monitor testmon { BACI podržava i Hoareove monitore s
void HelloA () { nekim ograniĉenjima.
cout << "Hello from A" <<endl;
Monitor je C— blok s nekim dodatnim
}
mogućnostima. Sve funkcije u
void HelloB () { monitorskim blokovima su vidljive
cout << "Hello from B" <<endl; spolja, ali monitorske varijable nisu
} pristupaĉne van bloka i mogu ih ĉitati
void HelloC () { samo monitorske funkcije.
cout << "Hello from C" <<endl;
} Monitor se može deklarisati samo na
globalnom nivou i monitori se ne mogu
}
gnijezditi.
main () {
cobegin { Samo jedna monitorska procedura se
HelloA(); može izvršavati u jednom trenutku, pa
HelloB(); se monitori mogu koristiti za uzajamno
HelloC(); iskljuĉivanje.
}
}
9.3.2016 36
USLOVNE VARIJABLE U
MONITORU
Dozvoljava procesu da ĉeka unutar monitora, monitor deklariše
uslovnu varijablu
condition x, y;
Uslovna varijabla može samo biti korišćena sa operacijama wait i
signal.
Operacija x.wait();
znaĉi da se proces koji je izvršio ovu operaciju, suspenduje dok
drugi proces ne izvrši operaciju X.signal();
Operacija x.signal nastavlja samo jedan suspendovan proces. Ako
nema suspendovanih procesa, onda operacija signal nema efekta
Budite svjesni: Uslovne varijable se razlikuju od mutex-a!
9.3.2016 37
MONITORI I USLOVNE
VARIJABLE U BACI
void A() { Tri konstrukcije se koriste za kontrolu
monitor simple_monitor { say_hello( 'A' ); konkurentnosti u monitoru condition
int finish; } varijable, waitc (wait on condition), i signalc
condition Cwait; void B() { (signal a condition).
void say_hello (char id) { say_hello( 'B' );
if ( id == 'C' ) { * condition varijables su pristupaĉne samo u
} monitorskim funkcijama. Condition
if ( finish != 2 ) void C() { varijabla nikada nema vrijednost, ona je
waitc( Cwait ); say_hello( 'C' ); prosto nešto na šta se ĉeka i što se
} signalizira.
}
cout << "hello from main() { * void waitc (condition cond, int prio):
process " << id << endl; cobegin { monitorski proces je blokiran i dodijeljen
if ( id != 'C' ) { mu je prioritet prio za ponovno buĊenje.
A(); B(); C(); Ova akcija blokiranja omogućava
finish++; } izvršavanje drugih monitorskih procesa
if ( finish == 2 ) cout << " all finished " << ako je neki spreman.
signalc( Cwait ); endl;
} * void waitc (condition cond): ista semantika
} kao waitc, ali se dodjeljuje podrazumijevani
} prioritet 10.
init {
finish = 0; * void signalc (condition cond): Probudi proces
koji ĉeka na cond , inaĉe ne radi ništa.
}
} * void empty (condition cond): Vraća 1 ako
nema procesa koji ĉekaju na condition
cond a 0 ako ih ima.
9.3.2016 38
ŠTA NAKON SIGNAL U
MONITORU
Neka je x uslovna varijabla. P0 izvršava jedan
x.signal() dok proces P1 je smješten u red ĉekanja
za x (kroz prethodni x.wait())
1. Hoare: Neka P1 se izvrši; suspenduj P0
2. Hansen: P0 mora izaći iz monitora, P1 se izvršava.
Operacija signal() može samo biti završni iskaz
monitorske funkcije
3. Mesa: Neka P0 se izvrši, poĉni P1 samo kada P0
izaĊe iz monitora
9.3.2016 39
BARIJERE
Korišćenje barijere
– Procesi se približavaju barijeri
– Svi procesi osim jednog se blokiraju na barijeri
Kada stigne poslednji proces tada su svi opet aktivni
Problem:
Gubitak vremena na procesoru ako su opterećenja nebalansirana
9.3.2016 40
KLASIĈNI PROBLEMI
SINHRONIZACIJE
Problem ograniĉenog bafera
ProizvoĊaĉ: u beskonaĉnoj petlji proizvodi
jedan element u svakoj iteraciji i smješta u
bafer
Potrošaĉ: u beskonaĉnoj petlji, troši elemente
iz bafera u svakoj iteraciji
Veliĉina bafera: može držati bar N elemenata
9.3.2016 41
Neadekvatno rješenje problema
ProizvoĊaĉ - Potrošaĉ
int itemCount = 0; procedure consumer() {
procedure producer() { while (true) {
while (true) { if (itemCount == 0) {
item = produceItem(); sleep();
if (itemCount ==
}
BUFFER_SIZE) {
sleep(); item = removeItemFromBuffer();
} itemCount = itemCount - 1;
putItemIntoBuffer(item);
if (itemCount == BUFFER_SIZE - 1) {
itemCount = itemCount + 1;
if (itemCount == 1) { wakeup(producer);
wakeup(consumer); }
}
consumeItem(item);
}
} }
}
9.3.2016 42
RJEŠENJE POMOĆU
SEMAFORA
9.3.2016 43
PROBLEM ĈITAĈ/PISAĈ
Ĉitaĉ: ĉita podatke
Pisaĉ: piše podatke
Pravilo:
Više ĉitaĉa mogu ĉitati podatke istovremeno
Samo jedan pisaĉ može pisati podatke u bilo kojem vremenu
Ĉitaĉ i pisaĉ ne mogu ući u kritiĉnu sekciju istovremeno
Pogledajmo u tabelu: da li bilo koja dva mogu biti u kritiĉnoj sekciji simultano
Ĉitaĉ Pisaĉ
Ĉitaĉ DA NE
9.3.2016
Pisaĉ NE NE 44
RJEŠENJE PROBLEMA
ĈITAĈ/PISAĈ
9.3.2016 45
PROBLEM 5 FILOZOFA
Filozofi jedu/misle
Da bi jeli trebaju 2 viljuške
U jednom trebutku podižu 1
viljušku
Da li je moguć zastoj?
Kako da se zastoj sprijeĉi?
9.3.2016 46
NETAĈNO RJEŠENJE
#define N 5 /* ukupno */
void philosopher(int i) /* i: broj filozofa, od 0 do 4 */
{
while (TRUE) {
think(); /* filozof razmišlja */
take_fork(i); /* uzima lijevu viljušku */
take_fork((i+1) % N);
/* uzmi desnu viljušku; % je modulo operator *
eat(); /* mmmmmmmmm */
put_fork(i); /* spuša lijevu viljušku na sto */
put_fork((i+1) % N); /* spušta desnu */
}
}
9.3.2016 47
TAĈNO RJEŠENJE
9.3.2016 48
TAĈNO RJEŠENJE nastavak
9.3.2016 49
MEĐUPROCESNA
KOMUNIKACIJA
ProsljeĊivanje poruka
Direktna komunikacija
Indirektna komunikacija
Komunikacija preko Mailbox-a
Prednosti indirektne
komunikacije
Baferovanje i veliĉina poruke
Asinhrone poruke
Problemi s porukama
9.3.2016 50
PROSLJEĐIVANJE PORUKA
IPC je najbolje ostvariva preko prosljeĊivanja poruka
―engl. messaging system‖
Sistem poruka i sistem djeljene memorije nisu
meĊusobno iskljuĉivi, i mogu se koristitisimultano
unutar jednog OS ili jednog procesa
Dvije osnovne operacije:
– Send (odredište, &poruka)
– Receive (izvor, &poruka)
Veliĉina poruke: fiksna ili promjenljive veliĉine.
Analogija sa stvarnošću: konverzacija
9.3.2016 51
PRIMJER PROSLJEĐIVANJA
9.3.2016 52
DIREKTNA KOMUNIKACIJA
Povezivanje algoritma imenu procesa
Pošiljaoc aksplicitno imenuje primaoca ili primaoc
eksplicitno imenuje pošiljaoca
Send(P,poruka)
Receive(Q,poruka)
Veza se uspostavlja automatski izmeĊu svakog para
procesa koji žele komunicirati
Procesi moraju znati identitete, jedan o drugom
Jedna veza po paru procesa
9.3.2016 53
INDIREKTNA KOMUNIKACIJA
(MAILBOX)
send(A,poruka) /* pošalji poruku u
mailbox A */
receive(A,poruka) /* prima poruku
iz mailbox-a A */
Mailbox je jedan apstraktni objekt
u koji se poruke mogu smjestiti ili
ukloniti.
Mailbox je vlasništvo ili procesa ili
sistema
Windows GUI osnovni stil
9.3.2016 54
BAFEROVANJE I VELIĈINA
PORUKA
Veza ima odreĊen kapacitet koji odreĊuje broj poruka koji semože nalaziti, privremeno
Red ĉekanja na poruke je pridružen vezi
Implementacija reda ĉekanja:
Red ĉekanja sa kapacitetom 0 (Zero capacity queues): veza ne može imati ni jednu
poruku koja ĉeka
Protokol: pošiljaoc mora ĉekati dok primaoc primi poruke, t.j. dva se procesa
moraju sinhronizirati za prenos poruka
Sinhronizacija se naziva ―RENDEZVOUS‖
Red ĉekanja ograniĉenog kapaciteta: veza može imati ‗n‘ poruka koje ĉekaju
Protokol: ako red ĉekanja nije pun, smjesti poslanu poruku u red ĉekanja; ako je
red ĉekanja pun, pošiljaoc ĉeka prostor u redu ĉekanja ne bude slobodan
Neograniĉen red ĉekanja: dužina reda ĉekanja je neograniĉena
Protokol: Pošiljaoc nikada ne ĉeka
9.3.2016 55
ASINHRONE PORUKE
Kod automatskog baferovanja, pošiljaoc ne zna da li je
poruka primljena
Koristi se mehanizam potvrde (engl. ACK -
acknowledgement)
Proces P:
– Send(Q,poruka)
– Receive(Q,poruka)
Process Q:
– Receive(P,poruka)
– Send(P,‖acknowledgement‖)
9.3.2016 56
PROBLEMI S PORUKAMA
Završetak procesa:
Pošiljalac završava, primalac ostaje blokiran.
Rješenje: Interni sat koliko ĉekati na poruku
Primalac završava, pošiljalac retransmituje.
Rješenje: mehanizam potvrde
Izgubljene poruke:
Rješenje: Retransmisija
Oštećene poruke:
Rješenje: CHECKSUM
9.3.2016 57
WINDOWS API ZA IPC PORUKE
GetMessage(lpMsg,hWnd, wMsgFilterMin, wMsgFilterMax)
Preuzima sljedeću poruku u redu ĉekanja na sve poruke izmeĊu prozora
i ĉeka ako nema poruka
PeekMessage(lpMsg,hWnd, wMsgFilterMin, wMsgFilterMax,wRemoveMsg)
Preuzima sljedeću poruku u redu ĉekanja na sve poruke izmeĊu prozora
ali ne ĉeka ako nema poruka
DispatchMessage(lpmsg)
Šalje narednu poruku u redu ĉekanja Windows sam odredi kojem
prozoru je namijenjena
SendMessage (hWnd, Msg,wParam,lParam)
Direktno šalje poruku navedenom prozoru
WM_COPYDATA, WM_DDE_DATA (oznake poruka namijenjenih za opšte
podatke)
WM_DDE_ADVISE, WM_DDE_INITIATE, inicijalizacija DDE prijenosa
9.3.2016 58
POSIX API ZA IPC PORUKE
mq_open(pcName, iOflag)
Povezuje se na red poruka
mq_close(mqdes)
Završava konekciju s otvorenim redom poruka
mq_unlink(pcName)
Završava konekciju s otvorenim redom poruka i nakon zadnje poruke
uklanja i red poruka
mq_send(mqdes, pcMsg_ptr,iMsg_len, uiMsg_prio)
Stavlja poruku u red poruka
mq_receive(mqdes, pcMsg_ptr,iMsg_len, pMsg_prio)
Prima i uklanja najstariju najprioritetniju poruku
mq_notify(mqdes, pSevp)
Izvještava proces ili nit da je poruka dostupna u redu ĉekanja
mq_setattr(mqdes, pNewattr, pOldattr)
mq_getattr(mqdes, struct mq_attr *attr)
Postavlja ili ĉita atribute reda ĉekanja poruka
9.3.2016 59
KOMUNIKACIJA POMOĆU
CIJEVI
Koncept pipe-a na komandnom nivou
Princip: Izlaz iz jedne komande se koristi za ulaz u drugu komandu
Primjer:
% who | sort
Ova kompleksna komanda je ekvivalentna nizu jednostavnih
komandi:
% who > tmpfile
% sort < tmpfile
% rm tmpfile
9.3.2016 60
POSIX API ZA RAD S CIJEVIMA
Neimenovana cijev se kreira Imenovana cijev se kreira sa dvije
metode:
sistemskim pozivom pipe()
1. Koristeći sistemski poziv mknod() ili
int p[2] ; /* niz pipe deskriptora biblioteĉnu funkciju mkfifo()
*/ 2. Korišćenjem shell komande mknod
res = pipe(p) ; /* kreiraj pipe */ (sa tastature)
Primjer kreiranja imenovanog pipe-a
/* p je pokazivaĉ na niz */ sa tastature:
res = 0, OK %mknod etf p kreira pipe pod
imenom ―etf‖
-1, nije OK
%ls –l
i p[0], p[1] su pridružene prw-r--r-- . . . etf
vrijednositi ulazu i izlaz
9.3.2016 61
/* Program sa neimenovanim pipe-ima */
#include <stdio.h>
#include <unistd.h>
main (){
int fd[2]; /* Niz od dva deskriptora za neimenovani pipe */
int pid;/* Variabla za identifikacu procesa */
/* Pipe treba kreirati prije bilo kojeg fork()-a */
if (pipe(fd) < 0){
perror ("PIPE – greška u kreiranju ");
exit (1);
}
pid = fork (); /* Proces roditelj: kreira se prvo dijete*/
if (pid == 0) { /* prvi process dijete počinje ovdje */
dup2 (fd[0],0); /* Standarni ulaz će se uzeti sa pipe-a */
close (fd[1]);/* Drugi kraj pipe-a će se zatvoriti za ovaj proces jer se neće koristiti */
execlp ("sort", "sort", 0); /* Pokreni “sort” komandu pipe */
}
else/* Ovdje process roditelj nastavlja */
pid = fork (); /* Proces roditelj: kreira 2. proces dijete */
if (pid == 0) { /* Drugi process dijete počinje ovdje */
dup2 (fd[1],1); /* Standarni izlaz će biti na kraju pipe-a*/
close (fd[0]); /* Ulaz u pipe je zatvoren jer se ne koristi */
execlp ("who", "who", 0);/* Komanda who šalje izlaz na pip-e*/
}
else { /* Proces roditelj zatvara pipe i čeka da djeca završe */
close (fd[0]);close (fd[1]);wait (0);wait (0);
}
}
WINDOWS API ZA RAD S
CIJEVIMA
Mailslot: virtuelna datoteka kojoj se šalju podaci koristeći
funkcije za pristup datotekama LPTSTR SlotName =
TEXT("\\\\.\\mailslot\\sample_mailslot");
CreatePipe(phReadPipe,phWritePipe,lpPipeAttributes,nSize)
Kreira neimenovanu cijev
CreateNamedPipe(lpName,dwOpenMode,dwPipeMode,
nMaxInstances,nOutBufferSize,nInBufferSize,nDefaultTimeOut,
lpSecurityAttributes)
Kreira imenovanu cijev
ConnectNamedPipe(hNamedPipe,lpOverlapped);
Server za imenovanu cijev
9.3.2016 63
FAZE KREIRANJA PIPE
Nakon uspostavljanja
jednosmjerne komunikacije
izmeĊu dva povezana
procesa.
Komunikacija se obavlja
sistemskim pozivima za
pristup datotekama:
write close fstat read fcntl
dup (Unix)
WriteFile ReadFile CloseFile
(Windows)
9.3.2016 64
SIGNALI U UNIXU
9.3.2016 65
OPŠTI OBLIK SIGNAL
FUNKCIJE
signal(<ime signala>,<odgovor na signal>) ;
<ime signala> ∈ {SIGINT, SIGKILL, SIGALARM, . . .
} ukupno 32
<odgovor na signal> =
SIG_IGN ignoriše ovaj signal,
SIG_DFL izvršava predefinisane akcije,
function izvršava ovu funkciju (može biti u
korisniĉkom programu).
9.3.2016 66
UPRAVLJANJE TOKOM PO
PRIJEMU SIGNALA
9.3.2016 67
SLANJE SIGNALA
kill (pid, id_signala)
Kako proces dijete šalje signal procesuroditelj
9.3.2016 68
UPOTREBA
#include <stdio.h>
#include <sys/signal.h> signal handler
void handler(int signum)
{
printf(―I got the interrupt signal\n‖) ;
signal(SIGINT, handler) ; Ponovno uspostavi handler
}
main()
{
int i ;
signal(SIGINT, handler) ;
for ( i=0 ; i<1000 ; i++)
{ printf(―working . . .%d\n‖, i) ;
sleep(1) ;
}
}
9.3.2016 69
ALARMI
Funkcija alarm(n) – će nakon isteka
nsekundi generisati signal SIGALRM
Ako je postavljen signalni handler za ovaj
signal onda ga možete uhvatiti i
koristitionako kako želite
9.3.2016 70
PRIMJER ALARMA
#include <signal.h>
int i, j;
void alarm_handler(int dummy){
printf("Tri sekunde su prošle: j = %d. i = %d\n", j, i);
signal(SIGALRM,alarm_handler);
}
main(){
signal(SIGALRM, alarm_handler);
alarm(3);
for (j = 0; j < 200; j++) { for (i = 0; i < 1000000; i++); }
}
UNIX> c3
Tri sekunde su prošle: j = 26. i = 638663UNIX>
9.3.2016 71