You are on page 1of 71

OPERATIVNI SISTEMI

SINHRONIZACIJA
PROCESA
I
MEĐUPROCESNA
KOMUNIKACIJA

9.3.2016 1
NADMETANJE ZA RESURSE

N thread-ova se natjeĉe da koristi iste djeljene


podatke
Stanje natjecanja je situacija gdje dva ili više

procesa ĉitaju i/ili pišu isti djeljeni podatak i


konaĉni rezultat zavisi od toga ko se izvršavao i
kada

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

 -c napravi .pob objektnu Primjer:


datoteku za naknadno bainterp konk.pco
linkovanje za PCODE (.pco) Ako se koristi Pascal sintaksa, izvorna datoteka ima
datotekom .pm sufiks, a kompajlira se bapas kompajlerom.
 Primjer:
 bacc konk.cm
9.3.2016 6
KRITIĈNA SEKCIJA

Proces {
while (true) {
ULAZAK U KRITIĈNU SEKCIJU
Pristup djeljenim var.; // Kritiĉna Sekcija;
IZLAZ IZ KRITIĈNE SEKCIJE
Izvršava druge poslove
}
}

Svaki thread ima segment koda, nazvan kritiĉna sekcija, u kojoj se


pristupa djeljenom podatku
Treba da obezbijedimo da kada jedan thread se izvršava u

kritiĉnoj sekciji, nijednom drugom thread-u nije dozvoljeno da se


izvršava u kritiĉnoj sekciji
9.3.2016 7
BACI PRIMJERI NESREĐENIH
KRITIĈNIH SEKCIJA
Svako izvršavanje je razliĉito. Nekada se prvo void HelloA () {
izvrši funkcija koja ispisuje slovo A, a int i,j;
nekada ona koja ispisuje slovo B ili C. I for (i=1;i<=5; i++) {
prekidi se dešavaju usred ispisa na ekran, for (j=1;j<=5; j++) cout << "A";
što se drastiĉnije vidi na desnom primjeru. cout << endl;
Ovo ilustruje borbu za resurs, u ovom }
sluĉaju ekran. }
void HelloB () {
void HelloA () { int i,j;
cout << "Hello from A" <<endl; for (i=1;i<=5; i++) {
} for (j=1;j<=5; j++) cout << "B";
void HelloB () { cout << endl;
cout << "Hello from B" <<endl; }
} }
void HelloC () { void HelloC () {
cout << "Hello from C" <<endl; int i,j;
} for (i=1;i<=5; i++) {
main () { for (j=1;j<=5; j++) cout << "C";
cobegin { cout << endl;
HelloA(); }
HelloB(); }
HelloC(); main () {
} cobegin {
} HelloA(); HelloB(); HelloC();
}
9.3.2016 } 8
ZAHTJEVI ZA KRITIĈNU
SEKCIJU
MeĊusobno iskljuĉivanje:
 Dok je proces u kritiĉnoj sekciji ni jedan drugi proces se ne smije izvršavati u njoj.
Napredak:
 Ako nema procesa koji ĉekaju na svoje kritiĉne sekcije i nekoliko procesa pokušava
da uĊe u kritiĉnu sekciju, onda ulazak u kritiĉnu sekciju ne može biti odlagan
beskonaĉno.
 Ni jedan proces koji se izvršava izvan svoje kritiĉne sekcije smije blokirati druge
procese
Ograniĉeno ĉekanje:
 Proces koji traži ulazak u kritiĉnu sekciju samo bi trebao da ĉeka na ograniĉen broj
drugih procesa da uĊu i izaĊu iz kritiĉne sekcije.
 Procesi ne bi trebali da ĉekaju beskonaĉno da bi ušli u kritiĉnu sekciju
Brzina i broj CPU-a:
 Pretpostavke ne bi smjele biti pravljene u vezi brzine i broja CPU-a.

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:

 Procesi većeg prioriteta ĉekaju da oni sa nižim prioritetom napuste

kritiĉnu sekciju
 Procesi nižeg prioriteta mogu da se nikad ne izvrše pošto oni sa

višim prioritetom se ne blokiraju


Rješenje: spavanje i buĊenje procesa (sleep & wakeup)

 Kada se proces blokira, ide u stanje spavanja

 Budi se kada je uslov ispunjen da bi pokušao ponovni ulazak u

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

ppid = geppid(); /* id mog roditelja?*/


kill (ppid, SIGUSR1); /* signal ka roditelju*/

Kako se ―nasilno završava program‖

kill (pid, SIGKILL) ili


kill (pid, 9)

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

You might also like