Operační systémy Přednášky pro výuku předmětu Operační systémy Ing. Antonín Vaněk, CSc. DFJP, Univerzita Pardubice září 2003
Kapitola 5 Konkurence procesů: vzájemné vylučování a synchronizace
Konkurence procesy si konkurují při: sdílení prostředků alokaci času procesoru komunikaci procesů synchronizaci více procesů
Interakce procesů procesy nevědí jeden o druhém interakce neexistuje procesy o sobě vědí jen nepřímo interakci zprostředkuje OS nebo jiný program procesy o sobě vědí přímo je možná přímá interakce
Zájmová sféra OS sledování aktivity procesů alokace a dealokace prostředků čas procesoru paměť I/O zařízení soubory ochrana dat a prostředků výsledek procesu nesmí záviset na rychlosti provádění... sdílí s ostatními procesy čas procesoru
Soutěžení procesů o prostředky provádění jednoho procesu může ovlivnit chování soupeřících procesů pokud přístup k jednomu prostředku požaduje více procesů současně, lze prostředek přidělit jen jednomu z nich ostatní procesy musí čekat ! nelze vždy zaručit, že blokovaný proces získá přístup k prostředku v budoucnosti takový proces nikdy neskončí, bude bez omezení čekat !
Problémy s konkurencí pokud přístup ke sdíleným prostředkům není řízen, může dojít k porušení konzistence dat výsledek akcí prováděných procesy může být závislý na pořadí, v jakém procesy dostanou přidělen procesor přístup ke sdíleným prostředkům je nutno řídit ! To je nepřípustné!
Příklad procesy P1 a P2 mají přístup ke stejné proměnné a a provádějí stejnou proceduru echo procesy mohou být kdykoliv (a tedy kdekoliv) přerušeny pokud je P1 po provedení operace vstupu přerušen, pak se provede P2 a nakonec se dokončí P1... ... proces P1 vypíše znak, načtený procesem P2 !! static char a; void echo() { cin >> a; cout << a; }
Problémy s řízením přístupu vzájemné vylučování (Mutual Exclusion) v každém okamžiku smí mít přistup k prostředku pouze jeden proces smrtící objetí (Deadlock) procesy vzájemně čekají na uvolnění prostředků, přidělených jiným procesům vyhladovění (Starvation) proces nemůže získat přístup k požadovanému prostředku v důsledku obsazení prostředku jinými procesy
Kooperace procesů sdílením procesy používají a mění sdílená data sdílené proměnné, soubory, databáze... v daném čase může data měnit pouze jeden proces např. textový soubor nesmí být otevřen pro zápis více editory současně k zajištění integrity dat se používají kritické sekce
Kooperace procesů komunikací vzájemná komunikace procesům umožňuje synchronizovat (koordinovat) různé aktivity může nastat smrtící objetí každý proces čeká na zprávu od některého jiného procesu ... žádný z procesů nemůže pokračovat může nastat vyhladovění dva procesy si stále vyměňují zprávy, zatímco jiný proces čeká na zprávu ... nikdy se jí nedočká
Kritická sekce proces je ve (své) kritické sekci (pro daný sdílený prostředek), jestliže provádí část programu, manipulující s (tímto) sdíleným prostředkem provádění kritické sekce musí být vzájemně výlučné (mutually exclusive) to platí i pro multiprocesorové prostředí každý proces musí žádat o povolení ke vstupu do kritické sekce ! v každém okamžiku smí být v kritické sekci (pro daný prostředek) pouze jeden proces
Obecná struktura procesu část programu, implementující protokol povolení přístupu, nazýváme vstupní sekce po vlastní kritické sekci (tj. úseku, kde dochází k vlastní manipulaci se sdíleným prostředkem) může následovat výstupní sekce zbytek kódu se označuje jako zbytková sekce repeat entry section critical section exit section remainder section forever
Rámec pro řešení procesy se provádějí nenulovou rychlostí nedělají se žádné zvláštní předpoklady o relativní rychlosti procesů může být použito i více procesorů, ale hardware paměti nesmí umožňovat současný přístup procesorů k jednomu paměťovému místu nedělají se žádné zvláštní předpoklady o prokládaném provádění stačí specifikovat vstupní a výstupní sekci
Požadované vlastnosti vzájemné vylučování (Mutual Exclusion) v kterémkoliv okamžiku může být v kritické sekci nejvýše jeden proces pokrok v přidělování pokud žádný proces není v kritické sekci a některé procesy tam chtějí vstoupit, na rozhodování o tom, který proces dostane povolení, se mohou podílet pouze procesy, které se nenacházejí ve zbytkové sekci toto rozhodování se musí uskutečnit v konečném čase omezené čekání poté, co proces požádal o přístup, smí před ním získat přístup pouze omezený počet procesů jinak by hrozilo vyhladovění
Typy řešení SW řešení algoritmy, jejichž korektnost nezávisí na dalších předpokladech (viz Rámec řešení) HW řešení využívá speciální instrukce procesoru OS řešení poskytuje programátorovi vhodné funkce a datové struktury
SW řešení: aktivní čekání Příklad: svého šamana (kritickou sekci) může v daném čase navštívit pouze jediný eskymák (proces) Igloo má malý vchod, takže dovnitř může vstoupit vždy jen jeden eskymák, aby si přečetl jméno napsané na tabuli Pokud je na tabuli jeho jméno, může jít k šamanovi Pokud je na tabuli napsáno jiné jméno, eskymák igloo opět opustí a čeká Čas od času eskymák znovu vstoupí do igloo podívat se na tabuli
SW řešení nejprve předpokládejme 2 procesy algoritmy 1 a 2 jsou nesprávné správný je algoritmus 3 (Petersonův) potom řešení zobecníme pro n procesů tzv. bakery algorithm nejprve pro 2 procesy: P0 a P1 když uvažujeme proces Pi, proces Pj vždy představuje ostatní procesy (i != j)
Algoritmus 1 sdílená proměnná turn je inicializována (na 0 nebo 1) před provedením libovolného procesu Pi kritická sekce CS procesu Pi se provádí, jestliže je turn = i Pi aktivně čeká (busy waiting) pokud je Pj v kritické sekci: požadavek na vzájemné vylučování je splněn požadavek pokroku není splněn, protože algoritmus vyžaduje přesné dodržení alternace kritických sekcí Process Pi: repeat while(turn!=i){}; CS turn:=j; RS forever
Algoritmus 1 - test příklad: předpokládejme, že P 0 má dlouhou zbytkovou sekci RS, P 1 krátkou pokud je turn=0, P 0 vstoupí do CS a pak provádí dlouhou RS (turn=1) zatím P 1 vstoupí do CS, provede krátkou RS (turn=0) a znovu se pokusí vstoupit do CS – ale požadavek je odmítnut ! P 1 musí čekat, dokud P 0 nedokončí RS
jedna booleovská proměnná flag pro každý proces: flag[0] a flag[1] signalizace připravenosti ke vstupu do CS nastavením flag[i]:=true požadavek na vzájemné vylučování je splněn požadavek na pokrok splněn není po sekvenci: P1: flag[1]:=true P0: flag[0]:=true budou oba procesy neomezeně čekat – máme deadlock Process Pi: repeat flag[i]:= true; while(flag[j]){}; CS flag[i]:= false; RS forever Algoritmus 2
Algoritmus 3 (Petersonův) Inicializace: flag[0]:=flag[1]:=false turn:= 0 nebo 1 signalizace připravenosti ke vstupu do CS nastavením flag[i]:=true Pokud se oba procesy pokusí vstoupit do CS současně, pouze jeden bude mít potřebnou hodnotu proměnné turn výstupní sekce: specifikuje, že Pi nechce vstoupit do sekce CS Process Pi: repeat flag[i]:=true; turn:=j; do {} while (flag[j]and turn=j); CS flag[i]:=false; RS forever
Algoritmus 3 – analýza správnosti požadavek na vzájemné vylučování je splněn není možné, aby P 0 a P 1 byly oba v CS nemůže nastat flag[0] = flag[1] = true a turn = i pro každý proces Pi plnění požadavků na pokrok a omezenost čekání Pi nemůže vstoupit do CS, pokud není současně flag[ j] = true a turn = j pokud Pj není připraven ke vstupu do CS, je flag[ j] = false a Pi proto může vstoupit do CS
pokud Pj nastavil flag[ j]=true a je ve while(), pak je buďto turn=i nebo turn=j je-li turn=i, pak Pi nevstupuje do CS (na řadě je Pj) ; pokud turn=j, pak Pj vstupuje do CS, ale při výstupu z CS nastaví flag[ j]=false a tím dovolí Pi vstoupit do CS když Pj nastavuje flag[ j]=true, nastavil již turn=i protože Pi po dobu čekání ve while() nemění nastavení turn, nemůže Pi vstoupit do CS, dokud nevstoupí do CS alespoň jednou také Pj (omezené čekání) Algoritmus 3 – analýza správnosti
Vliv chyb programu pokud jsou splněna všechna 3 kriteria (vzájemné vylučování, pokrok a omezené čekání), pak je řešení odolné proti chybám ve zbytkové sekci (RS) protože chyba v RS je vlastně totéž, co neomezeně dlouhá sekce RS bohužel řešení nemůže zajistit odolnost proti chybám v kritické sekci (CS) proces Pi, u kterého dojde k chybě v CS, signalizuje ostatním procesům tento fakt – Pi je pro tyto procesy stále v kritické sekci
Řešení pro n procesů t.zv. Bakery algoritmus před vstupem do kritické sekce dostane každý proces číslo. Držitel nejmenšího čísla může vstoupit do CS když Pi a Pj dostanou stejná čísla: pokud je i<j, má přednost Pi, jinak Pj ve výstupní sekci nastaví proces Pi přidělené číslo na 0
Bakery algoritmus poznámky k zápisu: (a,b) < (c,d) když a < c nebo když a = c a b < d max(a 0,...a k ) je číslo b takové, že platí b >= a i pro i=0..k sdílená data: choosing: array[0..n-1] of boolean; všechny prvky pole inicializovány na false number: array[0..n-1] of integer; všechny prvky pole inicializovány na 0 korektnost programu závisí na následujícím faktu: jestliže je Pi v CS a Pk si právě vybral své číslo number[k] != 0, pak (number[i],i) < (number[k],k) ale důkaz je poněkud složitý...
Process Pi: repeat choosing[i]:=true; number[i]:= max(number[0]..number[n-1])+1; choosing[i]:=false; for j:=0 to n-1 do { while (choosing[j]) {}; while (number[j]!=0 and (number[j],j)<(number[i],i)){}; } CS number[i]:=0; RS forever Bakery algoritmus
Nedostatky SW řešení Procesy požadující přístup do kritické sekce jsou v aktivním čekání (busy waiting) a proto zbytečně spotřebovávají čas procesoru pokud jsou kritické sekce dlouhé, může být efektivnější čekající procesy blokovat...
HW řešení opírá se o některé základní principy: proces běží v procesoru kontinuálně, dokud nevyvolá službu OS nebo není přerušen k přerušení procesu může dojít pouze na hranicích instrukcí mezi dokončením jedné a zahájením další instrukce přístup k paměťovému místu obvykle vylučuje současný přístup ostatních procesů k tomuto místu
Zákaz přerušení proces běží, dokud nevyvolá službu OS nebo není přerušen u jednoprocesorového systému zákaz přerušení zaručuje vzájemné vylučování u víceprocesorových systémů nezaručuje jsou omezeny možnosti procesoru prokládat programy zákaz přerušení může významně snížit efektivnost provádění programů v době, kdy je některý proces v kritické sekci, nelze procesor přidělit jinému procesu obecně nevhodné řešení prodlužuje se doba latence systému vadí tam, kde je požadována rychlá reakce (multimedia, RT systémy)
Process Pi: repeat disable interrupts CS enable interrupts RS forever Zákaz přerušení
Speciální instrukce přístup k paměťovému místu obvykle vylučuje přístup ostatních procesů k tomuto místu lze navrhnout instrukci procesoru, která provádí dvě akce (např. čtení a zápis) s jedním paměťovým místem jako atomickou (nedělitelnou) operaci provedení takové instrukce nelze přerušit a proto zaručuje vzájemné vylučování dokonce i při použití více procesorů takovou instrukci lze velmi jednoduše použít pro řešení problému vzájemného vylučování ... ale pro řešení dalších problémů kritické sekce (pokrok, omezené čekání) je nutné použít složitější programové konstrukce
Instrukce test-and-set jediná instrukce procesoru přečte příznak a současně ho nastaví pokud byl příznak nastaven už před provedením instrukce, nové nastavení nic nezmění kritická sekce je obsazena a proces proto musí čekat ... pokud ale příznak nastaven nebyl, může proces vstoupit do kritické sekce instrukce je nepřerušitelná a proto nemůže dojít k chybnému vyhodnocení příznaku lze použít u jedno- i víceprocesorových systémů lze použít pro více kritických sekcí
Instrukce test-and-set popis instrukce test-and-set v jazyce C++: bool testset(int& i) { if (i==0) { i=1; return true; } else { return false; }
Instrukce test-and-set Nevýhody jedná se o aktivní čekání, zabírající čas procesoru může dojít k vyhladovění když proces uvolní kritickou sekci, jako další získá povolení proces, který první provede instrukci v systému může vzniknout deadlock proces s nízkou prioritou má kritickou sekci, proces s vysokou prioritou žádá o povolení procesor je přidělen procesu s vysokou prioritou, kde pak čeká na uvolnění ale k tomu nemůže dojít, protože proces s nízkou prioritou nemůže získat procesor
algoritmus přístupu ke kritické sekci, vyžívající funkci testset sdílená proměnná b se inicializuje na 0 pouze první proces Pi (který nastaví b) vstupuje do kritické sekce Process Pi: repeat repeat{} until testset(b); CS b:=0; RS forever Instrukce test-and-set
Instrukce xchg instrukce xchg je dostupná u platformy Intel 86 sdílená proměnná b se inicializuje na 0 každý proces Pi má lokální proměnnou k do CS může vstoupit pouze proces, který najde b=0 tento proces Pi vyloučí přístup ostatních procesů Pj nastavením b=1 Process Pi: repeat k:=1 repeat xchg(k,b) until k=0; CS b:=0; RS forever
OS řešení: semafory synchronizační nástroj, nevyžadující aktivní čekání semafory poskytuje programům OS semafor je celočíselná proměnná, která je (s výjimkou inicializace) dostupná pouze prostřednictvím dvou atomických operací: wait(S) signal(S) aby se vyloučilo aktivní čekání, je proces, který musí čekat, blokován a zařazen do fronty procesů, čekajících na stejnou událost změnu stavu příslušného semaforu
Semafory ve skutečnosti je tedy semafor datovou strukturou typu záznam: type semaphore = record count: integer; queue: list of process end; var S: semaphore; když proces musí čekat na semafor S, je blokován a zařazen do fronty tohoto semaforu operce signal odstraní jeden proces z fronty a přesune ho do seznamu procesů připravených ke spuštění způsob výběru procesu určuje zvolená strategie, např. FIFO
Operace semaforu wait(S): S.count--; if (S.count<0) { block this process place this process in S.queue } signal(S): S.count++; if (S.count<=0) { remove a process P from S.queue place this process P on ready list } proměnnou count je nutné inicializovat na nezápornou hodnotu (aktuální hodnota závisí na potřebách aplikace)
Semafory: pozorování Když je S.count >=0, je počet procesů, které mohou provést wait(S) bez blokování roven S.count Když je S.count<0, je počet procesů čekajících na semafor S roven |S.count| Atomicita a vzájemné vylučování: žádné dva procesy nemohou být ve wait(S) a signal(S) (na tentýž S) ve stejném čase (platí i pro více procesorů) programové bloky definující wait(S) a signal(S) jsou ve skutečnosti kritické sekce
Semafory: pozorování kritické sekce definované ve wait(S) a signal(S) jsou velmi krátké typicky 10 instrukcí řešení: jednoprocesorové: zákaz přerušení po dobu provádění operace je to velmi krátká doba nelze použít u víceprocesorového systému víceprocesorové: použít některé z popsaných SW nebo HW řešení rozsah aktivního čekání nsmí být velký
Použití semaforů pro řešení problému kritické sekce Pro n procesů inicializuj S.count na 1 pak má pouze 1 proces povoleno vstoupit do CS (vzájemné vylučování) obecně platí, že inicializuj S.count na k lze povolit vstup do CS současně k procesům Process Pi: repeat wait(S); CS signal(S); RS forever
Použití semaforů pro synchronizaci procesů máme dva procesy: P1 a P2 příkaz S1 v P1 musí být proveden dříve než příkaz S2 v P2 definujeme semafor synch inicializujeme synch na 0 správnou synchronizaci zajistíme takto: P1: S1; signal(synch); P2: wait(synch); S2;
Binární semafory semafory, které jsme zatím používali, nazýváme čítací nebo celočíselné semafory (counting semaphores, integer semaphores) můžeme však použít i binární semafory podobné čítacím semaforům, pouze proměnná ”count” je typu boolean čítací semafory lze implementovat pomocí binárních semaforů... použití binárních semaforů je obvykle náročnější než čítacích např. je nelze inicializovat na hodnotu k > 1
Binární semafory waitB(S): if (S.value = 1) { S.value := 0; } else { block this process place this process in S.queue } signalB(S): if (S.queue is empty) { S.value := 1; } else { remove a process P from S.queue place this process P on ready list }
Spinlocks čítací semafory, používající aktivní čekání (busy waiting) místo blokování (blocking) jsou užitečné u víceprocesorových systémů, pokud kritická sekce netrvá dlouho aktivním čekáním sice ztratíme malé množství času CPU, ale ušetříme tím čas potřebný pro přepnutí procesů wait(S): S--; while S<0 do{}; signal(S): S++;
Problémy se semafory semafory jsou výkonným nástrojem pro řešení vzájemného vylučování a koordinace procesů wait(S) a signal(S) jsou rozděleny do více procesů a proto je obtížné porozumět jejich působení použití musí být korektní ve všech procesech jediný chybný proces může způsobit problémy s celým souborem procesů
Problém obědvajících filozofů 5 filozofů u stolu pouze jí nebo přemýšlí při jídle každý potřebuje 2 vidličky k dispozici je pouze 5 vidliček ilustruje obtížnost alokace prostředků procesům bez vzájemného zablokování či vyhladovění (deadlock, starvation) klasický synchronizační problém
Problém obědvajících filozofů každý filozof představuje jeden proces potřebujeme jeden semafor pro každou vidličku: fork: array[0..4] of semaphores Initialization: fork[i].count:=1 for i:=0..4 Process Pi: repeat think; wait(fork[i]); wait(fork[i+1 mod 5]); eat; signal(fork[i+1 mod 5]); signal(fork[i]); forever první pokus: když každý filozof začne tím, že uchopí vidličku po své levici, nastává deadlock
řešení: dovolit začít jíst pouze 4 filozofům najednou pak vždy alespoň 1 filozof může jíst, zatímco zbývající 3 musí čekat (s jednou vidličkou v ruce) musíme tedy použít další semafor (např. T), který umožní omezit počet filozofů Inicializace: T.count:=4 Process Pi: repeat think; wait(T); wait(fork[i]); wait(fork[i+1 mod 5]); eat; signal(fork[i+1 mod 5]); signal(fork[i]); signal(T); forever Problém obědvajících filozofů
Problém producenta a konzumenta dva typy procesů: producenti (producers) konzumenti (consumers) jeden nebo několik producentů produkuje data, která spotřebovává jeden nebo více konzumentů např. programy produkují znaky, které pak jsou spotřebovány (vytištěny) tiskárnou aby nevznikaly zbytečné čekací doby, je nutné zavést pro přechodné uskladnění produkovaných dat mezisklad - vyrovnávací paměť (buffer) pro řízení lze použít dva semafory jeden reprezentuje počet výrobků ve skladě druhý signalizuje, zda lze vstoupit do skladu
Nekonečná vyrovnávací paměť b[2]b[3]b[4] outin b[1]b[5].. šedá oblast indikuje, která část bufferu je obsazena vyrovnávací paměť (buffer) je pole, do kterého lze ukládat produkovaná data paměť musí mít nezávislý přístup pro zápis a čtení (unbounded buffer) in ukazuje na položku, do které se bude vkládat nový produkt out ukazuje na položku, která bude konzumována
Funkce producenta producer: repeat produce item v; b[in] := v; in := in + 1 forever;
Funkce konzumenta consumer: repeat while in <= out do { nothing }; w := b[out]; out := out + 1; consume item w forever;
Kruhová vyrovnávací paměť out in b[1]b[5] šedá oblast indikuje, která část bufferu je obsazena v praxi bývá velikost vyrovnávací paměti omezená paměť je propojena do kruhu (kruhový buffer) po n-té položce následuje opět první položka při zaplnění bufferu musí producent čekat ! b[2] b[3] b[4] b[n] b[n-1] směr rotace
Producent s kruhovým bufferem producer: repeat produce item v; while ( (in + 1) mod n = out) do { nothing }; b[in] := v; in := (in + 1) mod n forever;
Konzument s kruhovým bufferem consumer repeat while in = out do { nothing }; w := b[out]; out := (out + 1) mod n; consume item w forever;
Potřebujete oholit? u holiče jsou však jen 3 sedačky pro zákazníky a proto zde mohou obsluhovat pouze 3 holiči na pohovce je místo k sezení jen pro 4 čekající zákazníky ostatní zákazníci musí zůstat stát u dveří, dokud se neuvolní místo k sezení do místnosti se vejde celkem nejvýše 20 zákazníků, ostatní musí čekat venku nebo odejít pokladna pro placení je pouze jedna a inkasovat proto může pouze jeden holič
Barbershop Problem Vchod místo pro čekání ve stoje pohovka holící křesla Pokladna Východ
Barbershop Problem když je holič volný, přesune se nejdéle čekající zákazník z pohovky na křeslo nejdéle stojící zákazník pak usedne na pohovku v daném okamžiku může platit jen jeden zákazník holiči obsluhují zákazníky; pokud nečeká žádný zákazník, holiči spí
Co je nutné sledovat? kapacitu krámu a pohovky kapacitu holičů umístění právě jednoho zákazníka do volného křesla přítomnost zákazníka v křesle placení zákazníka po opuštění křesla přechod holiče na obsluhu pokladny
Barbershop Problem /* program barbershop1 */ semaphore max_capacity = 20; semaphore sofa = 4; semaphore barber_chair = 3; semaphore coord = 3; semaphore cust_ready = 0, finished = 0, leave_b_chair = 0, payment= 0, receipt = 0;
Customer void customer () { wait(max_capacity); enter_shop(); wait(sofa); sit_on_sofa(); wait(barber_chair); get_up_from_sofa(); signal(sofa); sit_in_barber_chair; signal(cust_ready); wait(finished); leave_barber_chair(); signal(leave_b_chair); pay(); signal(payment); wait(receipt); exit_shop(); signal(max_capacity) }
Barber void barber() { while (true) { wait(cust_ready); wait(coord); cut_hair(); signal(coord); signal(finished); wait(leave_b_chair); signal(barber_chair); }
Cashier void cashier() { while (true) { wait(payment); wait(coord); accept_pay(); signal(coord); signal(receipt); }
Monitory konstrukce ve vyšším programovacím jazyce, poskytující stejné služby jako semafory, ale je snadněji ovladatelná vyskytují se v řadě jazyků pro konkurenční programování (concurrent programming languages) Concurrent Pascal, Modula-3, uC++, Java... mohou být implementovány pomocí semaforů...
Monitor je softwarový modul, obsahující: jednu nebo více procedur inicializační sekvenci lokální datové proměnné charakteristiky: lokální proměnné jsou dostupné pouze prostřednictvím monitorových procedur proces vstupuje do monitoru vyvoláním některé jeho procedury v daném okamžiku může být v monitoru pouze jeden proces
Monitor monitor zajišťuje vzájemné vylučování program se tímto problémem nemusí zabývat sdílená data jsou chráněna tím, že se nacházejí v monitoru sdílená data jsou uzamčena v monitoru a procesy k nim mají přístup pouze prostřednictvím volání monitorových procedur synchronizaci procesů zajišťuje programátor použitím podmínkových proměnných reprezentují podmínky, které proces musí splnit před vstupem do monitoru
Podmínkové proměnné Condition variables jsou lokálními proměnnými monitoru (dostupné pouze v monitoru) lze k nim přistupovat a měnit je pouze následujícími 2 funkcemi: cwait(a) blokuje provádění volajícího procesu podmínkou (proměnnou) a proces může být znovu aktivován pouze když jiný proces provede csignal(a) csignal(a) obnoví provádění některého procesu blokovaného podmínkou (proměnnou) a pokud takových procesů existuje více, je vybrán jeden z nich pokud žádný takový proces neexistuje, neprovede se nic
Monitor čekající procesy jsou buď ve vstupní frontě nebo v podmínkové frontě proces se umísťuje do podmínkové fronty c n sám provedením cwait (c n ) csignal (c n ) vpustí do monitoru jeden z procesů čekajících ve frontě c n csignal (c n ) tedy blokuje volající proces a umísťuje ho do urgentní fronty (pokud ovšem csignal není poslední operaci monitorové procedury)
řešíme problém producentů a konzumentů pro synchronizaci použijeme monitor append() a take() jsou procedury monitoru jsou to jediné procedury, umožňující procesům přístup k vyrovnávací paměti pokud jsou tyto procedury korektní, bude synchronizace korektní pro všechny zúčastněné producenty i konzumenty ProducerI: repeat produce v; Append(v); forever ConsumerI: repeat Take(v); consume v; forever Monitor a problém svázaných P/C
Monitor potřebuje vyrovnávací paměť (sklad): buffer: array[0..k-1] of items; potřebuje dvě podmínkové proměnné: notfull csignal(notfull) indikuje že buffer není plný notempty csignal(notempty) indikuje, že buffer není prázdný potřebuje ukazatele do bufferu a čítače: nextin ukazuje na první volné místo pro přidávání nextout ukazuje na aktuální položku k odebrání count obsahuje počet položek v bufferu
Monitor boundedbuffer: buffer: array[0..k-1] of items; nextin:=0, nextout:=0, count:=0: integer; notfull, notempty: condition; Append(v): if (count=k) cwait(notfull); buffer[nextin]:= v; nextin:= nextin+1 mod k; count++; csignal(notempty); Take(v): if (count=0) cwait(notempty); v:= buffer[nextout]; nextout:= nextout+1 mod k; count--; csignal(notfull); Monitor a problém svázaných P/C
Předávání zpráv je nutné vzájemné vylučování dochází k výměně informací send (destination, message) receive (source, message)
vysílač a/nebo přijímač může (ale nemusí) být blokován neblokující send, neblokující receive neblokující send, blokující receive vysílač po odeslání zprávy pokračuje aby mohl připravovat zprávy co nejrychleji přijímač je blokován, dokud zpráva není doručena aby mohl okamžitě reagovat na doručení zprávy blokující send, blokující receive na doručení zprávy čeká přijímač i vysílač (rendezvous) Synchronizace při předávání zpráv
Adresace přímá adresace funkce send zahrnuje specifický identifikátor cílového procesu funkce receive může předem určit, od kterého procesu je zpráva očekávána zprávy od jiných procesů mohou být ignorovány speciální adresa (např. 0) specifikuje, že zpráva může přijít od kteréhokoliv procesu funkce receive může při volání dostat parametrem hodnotu, kterou má předat, když byla zpráva přijata to umožňuje při neblokujícím receive zjistit, že došla zpráva
Adresace nepřímá adresace zprávy se zasílají do sdílené datové struktury, skládající se z front říkáme jim poštovní schránky (mailboxes) jeden proces posílá zprávy do schránky, druhý si zprávy ze schránky vyzvedává
Mailboxy a porty mailbox může být vlastněn jedním párem vysílač/přijímač tentýž mailbox může být sdílen několika vysílači a přijímači OS pak může dovolit rozlišení více typů zpráv Port je mailbox svázaný s jedním přijímačem a více vysílači používá se pro aplikace typu klient/server (server je přijímačem)
Vlastnictví portů a mailboxů port je obvykle vlastněn přijímačem port se ruší ukončením procesu přijímače mailbox vytváří OS na žádost procesu, který se tak stává jeho vlastníkem mailbox se ruší na žádost procesu- vlastníka nebo když je tento proces ukončen
Obecný formát zprávy Message Contents záhlaví zprávy tělo zprávy Message Type Destination ID Source ID Message Length Control Info.
Problém čtenářů a pisatelů jakýkoliv počet čtenářů může souběžně číst obsah souboru v daném čase může do souboru zapisovat pouze jeden pisatel pokud pisatel zapisuje do souboru, nemůže jeho obsah číst žádný čtenář
Dosažení vzájemného vylučování přenosem zpráv vytvoření mailboxu mutex sdíleného n procesy send() is neblokující receive() je blokující když je mailbox mutex prázdný Inicializace: send(mutex, “go”); První proces P i, který provede receive() může vstoupit do CS ostatní procesy budou blokovány dokud P i neodešle zprávu Process Pi: var msg: message; repeat receive(mutex,msg); CS send(mutex,msg); RS forever
Problém svázaných P/C přenosem zpráv producenti umisťují položky odesíláním zpráv do mailboxu mayconsume mailbox mayconsume slouží jako buffer: konzument může konzumovat, jestliže je v mailboxu alespoň jedna zpráva Na začátku je mailbox mayproduce naplněn k prázdnými zprávami (k= velikost bufferu) počet položek v bufferu se zvětší každým příchodem zprávy a zmenší každým odebráním zprávy může obsluhovat více producentů i více konzumentů
Producer: var pmsg: message; repeat receive(mayproduce, pmsg); pmsg:= produce(); send(mayconsume, pmsg); forever Consumer: var cmsg: message; repeat receive(mayconsume, cmsg); consume(cmsg); send(mayproduce, null); forever Problém svázaných P/C přenosem zpráv