10.07.2015 Views

2× DVD - Vitajte na stránkach www.einsty.hostujem.sk

2× DVD - Vitajte na stránkach www.einsty.hostujem.sk

2× DVD - Vitajte na stránkach www.einsty.hostujem.sk

SHOW MORE
SHOW LESS
  • No tags were found...

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

P R O G R A M U J E M EDôleitá poznámka: Je nevyhnutné zabezpeèi, aby sa k premenným a objektom, <strong>sk</strong>torými pracujeme v kritickej sekcii, dalo v programe pristupova len cez príkazy synchronized,ktoré <strong>na</strong>vyše musia pracova s rov<strong>na</strong>kým zamykacím objektom. V opaènomprípade synchronizácia stráca zmysel.MONITORY. V paralelnom programovaní pojem monitor opisuje údajovú metaštruktúru,ktorú by sme mohli pripodobni k javov<strong>sk</strong>ej triede: monitor má vnútorný stav (údajové èleny)a po<strong>sk</strong>ytuje operácie, ktoré mono <strong>na</strong>d monitorom vykonáva (metódy). Podstatným rozdie−lom oproti triedam je zabezpeèenie vzájomného vyluèovania pri prístupe k monitoru. I<strong>na</strong>kpovedané: z metód monitora môe by súèasne volaná <strong>na</strong>jviac jed<strong>na</strong>.Implementácia monitorov v Jave je logickým dôsledkom pouitia mechanizmu zám−kov. Ak sa zamyslíme <strong>na</strong>d tým, ako by sa dalo vzájomné vyluèovanie pri prístupe k metó−dam triedy realizova, rýchlo prídeme <strong>na</strong> <strong>na</strong>jjednoduchšiu monos: obali kód metódy dopríkazu synchronized a ako zamykací objekt poui this. Ide to však ešte jedno−duchšie. Ak pri deklarácii metódy pouijeme ako jeden z modifikátorov k¾úèové slovosynchronized, dosiahneme tým, e pri volaní metódy sa aktuálny thread <strong>na</strong>jprv pokú−si zí<strong>sk</strong>a zámok <strong>na</strong>d objektom, <strong>na</strong>d ktorým metódu volá. V prípade, e ide o statickúmetódu, v rámci ktorej objekt this neexistuje, ako zamykací objekt sa pouije objekttypu Class reprezentujúci danú triedu.Ako jednoduchý príklad monitora si ukáme triedu, ktorá vyrieši náš predchádzajúciproblém s paralelnou inkrementáciou premennej x:class MutExVar{private int value;public MutExVar(int _val){ value = _val; }public synchronized void set(int _val){ value = _val; }public synchronized int get(){ return value; }public synchronized void inc(){ value ++; }}Oba thready budú <strong>na</strong>miesto príkazu x = x + 1 v cykle vola metódu x.inc() (pred−pokladáme, e x je teraz inštanciou triedy MutExVar). Ïalšie synchronizované metódyset() a get() slúia <strong>na</strong> <strong>na</strong>stavenie a zí<strong>sk</strong>anie uloenej hodnoty. Konštruktor z pocho−pite¾ných dôvodov nemusí by synchronizovaný.PROBLÉM S DEADLOCKOM. Pri práci so zámkami sa treba vyvarova situá−cie, ktorá sa bene oz<strong>na</strong>èuje anglickým termínom deadlock, po sloven<strong>sk</strong>y uviaznutie.Okolo problému deadlocku existuje celá teória, take len struène: stav deadlocku z<strong>na</strong>me−ná, e jeden alebo viacero threadov neobmedzene dlho èaká <strong>na</strong> vstup do kritickej sekcie(a nikdy sa do nej nedostane).Ako môe k deadlocku dôjs? Predstavme si dva thready, ktoré <strong>na</strong> vstup do kritickejsekcie potrebujú zí<strong>sk</strong>a dva zámky, ale budú to robi v <strong>na</strong>vzájom opaènom poradí. Prvýthread <strong>na</strong>príklad takto:synchronized (lock1){synchronized (lock2){// ...}}a druhý takto:synchronized (lock2){synchronized (lock1){// ...}}Ak sa prvému threadu podarí zí<strong>sk</strong>a lock1 a druhému lock2, v tom okamihu súodsúdení <strong>na</strong> veèné èakanie, pretoe ani jeden nemôe zí<strong>sk</strong>a druhý zámok (má ho tendruhý). Vyriešenie tohto konkrétneho problému je jednoduché – staèí zameni poradiepríkazov synchronized v niektorom z threadov. Univerzálny liek však <strong>na</strong> odstránenienebezpeèenstva deadlocku neexistuje a pri písaní programov treba pouíva predovšet−kým zdravý rozum a riadnu dávku predstavivosti.PODMIENEÈNÉ PREMENNÉ. Java po<strong>sk</strong>ytuje ešte jeden synchronizaèný pro−striedok, ktorý sa <strong>na</strong>jviac podobá konceptu podmieneèných premenných (conditio<strong>na</strong>lvariables). Tie si môeme predstavi ako metaobjekty, ktoré predstavujú synchronizaèné bodyviazané <strong>na</strong> splnenie nejakej podmienky. Po<strong>sk</strong>ytujú dve operácie s tradiènými názvami waita sig<strong>na</strong>l, ktorým v Jave zodpovedajú metódy wait() a notify(). Ide o metódy triedyObject, a teda ich môeme zavola <strong>na</strong>d kadou inštanciou objektového typu.Aká je sémantika týchto dvoch operácií? Ak thread zistí, e podmienka, ktorá je pridruenák podmieneènej premennej, nie je splnená, vykoná operáciu wait. Tým sa zaradí do zoz<strong>na</strong>muèakate¾ov <strong>na</strong> danú podmieneènú premennú, prejde do stavu „spiaci“ a <strong>na</strong>ïalej nesúaí opridelenie procesora. Zo spánku ho môe zobudi iný thread, ktorý <strong>na</strong>d podmieneènou pre−mennou vykoná operáciu sig<strong>na</strong>l. Dôsledkom tejto operácie je výber jedného z èakate¾ov ajeho zobudenie. Zobudený thread sa presúva do stavu „pripravený“ a èaká <strong>na</strong> pridelenie pro−cesora. Ak je zoz<strong>na</strong>m èakate¾ov prázdny, operácia sig<strong>na</strong>l nemá nijaký efekt.Pozrime sa teraz <strong>na</strong> vec <strong>na</strong> úrovni zdrojového kódu. Operácii wait zodpovedá zavola−nie metódy wait() <strong>na</strong>d ¾ubovo¾ným objektom (ktorý <strong>na</strong>hrádza spomí<strong>na</strong>nú podmieneè−nú premennú). Aktuálny thread musí <strong>na</strong>d týmto objektom vlastni zámok. V rámci vyko−návania metódy je thread pozastavený a zámok sa mu odoberie (to je nevyhnutný krok,pretoe i<strong>na</strong>k by spiaci thread blokoval akýko¾vek prístup k synchronizaènému objektu).Pri volaní metódy wait() mono ako volite¾ný argument zada maximálny èas, poèa<strong>sk</strong>torého thread bude èaka <strong>na</strong> zobudenie.Druhej operácii sig<strong>na</strong>l zodpovedá metóda notify(), ktorú, pochopite¾ne, voláme <strong>na</strong>drov<strong>na</strong>kým objektom ako metódu wait(). Thread, ktorý metódu volá, tak obyèajne èinípreto, lebo zabezpeèil splnenie podmienky pridruenej k objektu. Ako dôsledok volaniametódy notify() sa zobudí jeden z èakajúcich threadov (ktorý to bude, je vecou imple−mentácie). Ak nikto neèaká, metóda je bez efektu. Niekedy príde vhod zobudi všetky èakajú−ce thready – vtedy pouijeme metódu notifyAll(), ktorá sa i<strong>na</strong>k správa ako metódanotify(). Metódy notify() a notifyAll() by mal vola len thread, ktorý je momen−tálne vlastníkom zámku <strong>na</strong>d synchronizaèným objektom.Zobudený thread nezaène bea okamite. Je zaradený do radu threadov èakajúcich<strong>na</strong> <strong>na</strong>plánovanie a po pridelení procesora sa <strong>na</strong>jprv s<strong>na</strong>í zí<strong>sk</strong>a zámok, ktorý mu bolpred pozastavením odobraný. Po zí<strong>sk</strong>aní zámku ukonèí volanie metódy wait() apokraèuje <strong>na</strong>sledujúcim príkazom. V prípade, e thread volal metódu wait() ako dôsle−dok nesplnenia nejakej podmienky, je ve¾mi dôleité test podmienky zopakova, pretoenie je zaruèené, e sa od okamihu zobudenia threadu po jeho opätovné <strong>na</strong>plánovanietáto podmienka nezmenila. Namiesto kódu:synchronized ( obj ){if (! podmienka )obj.wait();}treba bezpodmieneène poui kód:synchronized ( obj ){while (! podmienka )obj.wait();}A ešte jed<strong>na</strong> poznámka <strong>na</strong> záver: Threadu sa poèas vykonávania metódy wait() odo−berá len zámok <strong>na</strong> aktuálny objekt. Prípadné ïalšie zámky mu zostávajú a sú tak dobrýmkandidátom <strong>na</strong> vznik deadlocku.PRÍKLADY. Zdrojové texty k príkladom mono tradiène nájs <strong>na</strong> webovej stránke PCREVUE. Nachádza sa tam okrem iného riešenie klasického problému synchronizácie prístupuku koneènému bufferu (i<strong>na</strong>k známeho aj ako problém producentov/konzumentov).Vladimír Klimov<strong>sk</strong>ý112 PC REVUE 1/2002

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!