10. előadás Párhuzamos programozási kérdések. Az Ada taszkok (1).
2 FEJTÖRŐ ?
3 Párhuzamos programozás n Program: több tevékenység egyidőben n Önálló folyamatok n Együttműködnek n Többféle lehetőség – Elosztott rendszer (distributed system) – Többszálú program (multithreaded program) – … n Célok – Hatékonyság növelése – A feladat egyszerűbb megoldása
4 Elosztott rendszer n Több számítógép hálózatba szervezve n A folyamatok elosztva a hálózaton n Kliens-szerver programok n Elosztott objektumrendszer (CORBA, DCOM) n PVM, MPI, messaging rendszerek n Ada 95: Partíciók n Kommunikáció: – Távoli eljáráshívás (Remote Procedure Call) – Üzenetküldés
5 Többszálú programok n Egy processzen belül több végrehajtási szál n Operációs rendszerek is támogathatják n Programozási nyelvi eszközök (Ada, Java) n Egy tárterületen belül futnak – A processzhez rendelt memóriában – Megosztott memóriás modell – Saját végrehajtási verem
6 Mire jó a több szál n Ha több tevékenységet kell végezni egyszerre n Egymástól függetlenül fogalmazhatjuk meg ezeket n Összehangolásra szükség van: – Szinkronizáció – Kommunikáció n Példák – Több kliens kiszolgálása a szerverben – Webböngésző: a felhasználói felület kezelése + letöltés – Szimulációk
7 Problémák n Elméleti nehézség (programhelyesség) n Gyakorlati nehézség (nemdeterminisztikusság) tesztelés, nyomkövetés n Ütemezés n Interferencia n Szinkronizáció n Kommunikáció
8 Ada taszkok n A többszálú programozáshoz nyelvi eszköz n Gazdag lehetőségek task A; task body A is begin for I in loop Put_Line("Szia!"); end loop; end A;
9 Taszk programegység n Specifikáció és törzs – Különválik (mint a csomag és a sablon) task A;task body A is … end A; – Specifikáció: hogyan lehet vele kommunikálni – Törzs: hogyan működik n Nem lehet könyvtári egység (be kell ágyazni más programegységbe)
10 Kétszálú program with Ada.Text_IO; use Ada.Text_IO; procedure Kétszálú is task Egyik; task body Egyik is begin loop Put_Line("Szia!"); end loop; end Egyik; begin loop Put_Line("Viszlát!"); end loop; end Kétszálú;
11 Lehetséges kimenetek Szia! Viszlát! Szia! Viszlát! Szia! Viszlát! Szia! Viszlát! Szia! Viszlát! Szia! Viszlát! Szia! Viszlát! Szia! Viszlát! Szia! SziViszla! át! Szia! Viszlát! ViszSzia! láSzit!a! Szia!
12 Jellemző kimenet n Sokszor az egyik (például Viszlát!) n Utána sokszor a másik n Nem ugyanannyiszor n Változik futás közben, hogy melyikből mennyi n Futásról futásra is változik
13 Ütemezés n A futtató rendszer ütemezi a szálakat – Vagy az oprendszer, vagy az Ada rendszer – Co-rutinok: programozó ütemez (Simula 67) n Az Ada nyelv nem tesz megkötést arra, hogy egy adott Ada implementációban az ütemezés milyen algoritmussal történik n Jó program: bármely ütemezésre jó
14 Időosztásos ütemezés n Nem valódi párhuzamosság n Egy processzor: egyszerre csak egyet n Időszeletek (time slicing) n Gyorsan váltogatunk, párhuzamosság látszata n Egyenlő időszeletek: pártatlanság
15 Kompetitív viselkedés n „Fusson, amíg van mit csinálnia” n Amíg számol, addig övé a vezérlés n Vezérlés elvétele: csak speciális pontokon (szinkronizáció) n Hatékonyabb, mint az időszeletes ütemezés n Nem pártatlan: egy taszk kisajátíthatja az erőforrásokat
16 Pártatlanság, kooperáció n Egy taszk lemondhat a vezérlésről n delay utasítás loop Put_Line("Szia!"); delay 0.0; end loop; n Jellemző kimenet: felváltva írnak ki
17 Várakozás n Egy időre felfüggeszthető a taszk n A delay utasítással: delay 2.4; n A delay után Duration típusú érték van – Predefinit valós fixpontos típus – A másodperc megfelelője n Legalább ennyi ideig nem fut a taszk n Szimulációkban gyakran használjuk n Használjuk szinkronizációs utasításokban
18 Taszk elindulása és megállása procedure P is task T; task body T is … begin … end T; begin … end P; itt indul a T P itt bevárja T-t
19 Szülő egység n Az a taszk / alprogram / könyvtári csomag / blokk, amelyben deklaráltuk – (!) n Elindulás: a szülő deklarációs részének kiértékelése után, a szülő első utasítása előtt n A szülő nem ér véget, amíg a gyerek véget nem ér n Függőségi kapcsolatok
20 Taszk befejeződése n Bonyolult szabályok n Fogalmak: komplett, abortált, terminált n Például: – elfogytak az utasításai (akár kivétel miatt) – és a tőle függő taszkok már termináltak n T’Callable – akkor hamis ha a taszk már kompletté vált n T’Terminated – akkor igaz, ha a taszk már terminált
21 Ha több egyforma szál kell with Ada.Text_IO; use Ada.Text_IO; procedure Háromszálú is task Egyik; task body Egyik is begin loopPut_Line("Szia!");end loop; end Egyik; task Másik; task body Másik is … begin … end Másik; begin loopPut_Line("Viszlát!"); end loop; end Háromszálú;
22 Taszk típussal with Ada.Text_IO; use Ada.Text_IO; procedure Háromszálú is task type Üdvözlő; task body Üdvözlő is begin loopPut_Line("Szia!");end loop; end Üdvözlő; Egyik, Másik: Üdvözlő; begin loopPut_Line("Viszlát!"); end loop; end Háromszálú;
23 Taszk típus n Taszkok létrehozásához – Ugyanazt csinálják, ugyanolyan utasítássorozatot hajtanak végre – Saját példánnyal rendelkeznek a lokális változókból n Korlátozott (limited) típusok n Cím szerint átadandó, ha alprogram-paraméter n Programegységek – Mint a taszk programegységek – Specifikáció és törzs különválik – Nem lehet könyvtári egység (be kell ágyazni más programegységbe)
24 Taszk típus diszkriminánsai n Mint a rekordok esetében n Lehet a diszkrimináns mutató típusú is n Taszkok létrehozásakor aktuális task type T ( Id: Integer ); task body T is … begin … Put(Id); … end T; X: T(13);
25 Mutató típusú diszkrimináns with Ada.Text_IO; use Ada.Text_IO; procedure Háromszálú is type PString is access String; task type Üdvözlő ( Szöveg: PString ); task body Üdvözlő is begin loopPut_Line(Szöveg.all);end loop; end Üdvözlő; Egyik: Üdvözlő(new String’("Szia!")); Másik: Üdvözlő(new String’("Hello!")); begin loopPut_Line("Viszlát!");end loop; end Háromszálú;
26 Taszkok létrehozása allokátorral n Taszk típusra mutató típus: task type Üdvözlő ( Szöveg: PString ); type Üdvözlő_Access is access Üdvözlő; P: Üdvözlő_Access; n A mutató típus gyűjtőtípusa egy taszk típus n Az utasítások között: P := new Üdvözlő( new String’("Szia!") );
27 Taszk elindulása és megállása procedure Fő is task type Üdvözlő ( Szöveg: PString ); type Üdvözlő_Access is access Üdvözlő; P: Üdvözlő_Access; task body Üdvözlő is … begin … end; begin … P := new Üdvözlő( new String’("Szia!") ); … end Fő; itt indu l Fő itt bevárja
28 Szülő egység n Az a taszk / alprogram / könyvtári csomag / blokk, – amelyben deklaráltuk – amely a mutató típust deklarálta n Elindulás: – a szülő deklarációs részének kiértékelése után, a szülő első utasítása előtt – az allokátor kiértékelésekor n A szülő nem ér véget, amíg a gyerek véget nem ér n Függőségi kapcsolatok, befejeződés
29 Komplett taszk n Ha véget ért a törzs utasításainak végrehajtása – normálisan – kivételes eseménnyel n és nincs kivételkezelő rész n vagy van, de nincs megfelelő ág benne n vagy van, és a kivételkezelő ág lefutott n Ha a taszk elindítása során kivétel lépett fel
30 Abnormális állapotú taszk n Az abort utasítással „kilőhető” egy taszk – akár magát is kilőheti: öngyilkos n Nem túl szép módja egy taszk leállításának task type T( Id: Integer ); task body T is... end T; X: T(1); Y: T(2); begin … abort X, Y;
31 Egy taszk terminál, ha n komplett, és az összes tőle függő taszk terminált már n abnormális állapotba jutott és törlődött a várakozási sorokból n terminate utasításhoz ért, és a taszk olyan programegységtől függ, amely már komplett, és a leszármazottai termináltak már, komplettek, vagy szintén terminate utasításnál várakoznak
32 Szülő terminálása n Egy szülő addig nem terminálhat, amíg az általa létrehozott taszkok nem terminálnak n Miután befejezte saját utasításainak végrehajtását (azaz kompletté vált), megvárja, hogy a tőle függő taszkok is termináljanak (az end-nél várakozik)
33 Információcsere taszkok között n Nonlokális (globális) változókon keresztül – Nem szeretjük... n Randevúval – Ezt fogjuk sokat gyakorolni – Aszimmetrikus, szinkron, pont-pont, kétirányú kommunikációt tesz lehetővé n Védett egységek használatával
34 Nonlokális változón keresztül procedure P is N: Natural := 100; task type T; task body T is begin … if N > 0 then N := N-1; … end if; … end T; A, B: T; begin … end P; legfeljebb N-szer szabadna
35 FEJTÖRŐ ?
36 Interferencia n Ha a taszkok önmagukban jók n De együttes viselkedésük rossz n Szinkronizáció segíthet
37 Randevú n Szinkronizációhoz és kommunikációhoz n Egyik taszk: belépési pont (entry) és accept utasítás n Másik taszk: meghívjuk a belépési pontot n Aszimmetrikus n Szinkron n Pont-pont n Kétirányú
38 task Lány is entry Randi; end Lány; task body Lány is begin … accept Randi; … end Lány; task Fiú; task body Fiú is begin … Lány.Randi; … end Fiú; Fiú és lány taszkok
39 task Lány is entry Randi; end Lány; task body Lány is begin … accept Randi; … end Lány; task Fiú is end Fiú; task body Fiú is begin … Lány.Randi; … end Fiú; Fiú és lány taszkok
40 Pont-pont kapcsolat n Egy randevúban mindig két taszk vesz részt n Egy fiú és egy lány n Szerepek – Egy taszk lehet egyszer fiú, másszor lány n Nincs "broad-cast" jellegű randevú
41 Aszimmetrikus n Megkülönböztetjük a hívót és a hívottat (fiú és lány) n Egész másként működik a két fél n A szintaxisban is kimutatható a különbség n A hívó ismeri a hívottat, de fordítva nem
42 Az accept törzse n A randevú az accept utasítás végrehajtásából áll n Ez alatt a két taszk „együtt van” n A fogadó taszk hajtja végre az accept-et n Az accept-nek törzse is lehet, egy utasítássorozat
43 task Lány is entry Randi; end Lány; task body Lány is begin … accept Randi do … end; … end Lány; task Fiú; task body Fiú is begin … Lány.Randi; … end Fiú; Huzamosabb randevú
44 Szinkronitás n A randevú akkor jön létre, amikor mindketten akarják n Bevárják egymást a folyamatok az információcseréhez n Az aszinkron kommunikációt le kell programozni, ha szükség van rá
45 A lány bevárja a fiút (1) FiúLány Lány.Randi;accept Randi do … end Randi;
46 A lány bevárja a fiút (2) FiúLány Lány.Randi;accept Randi do … end Randi;
47 A lány bevárja a fiút (3) FiúLány Lány.Randi;accept Randi do … end Randi;
48 A lány bevárja a fiút (4) FiúLány Lány.Randi;accept Randi do … end Randi;
49 A lány bevárja a fiút (5) FiúLány Lány.Randi;accept Randi do … end Randi;
50 A lány bevárja a fiút (6) FiúLány Lány.Randi;accept Randi do … end Randi;
51 A fiú bevárja a lányt (1) FiúLány Lány.Randi;accept Randi do … end Randi;
52 A fiú bevárja a lányt (2) FiúLány Lány.Randi;accept Randi do … end Randi;
53 A fiú bevárja a lányt (3) FiúLány Lány.Randi;accept Randi do … end Randi;
54 A fiú bevárja a lányt (4) FiúLány Lány.Randi;accept Randi do … end Randi;
55 A fiú bevárja a lányt (5) FiúLány Lány.Randi;accept Randi do … end Randi;
56 A fiú bevárja a lányt (6) FiúLány Lány.Randi;accept Randi do … end Randi;
57 Kommunikáció n A randevúban információt cserélhetnek a taszkok n Paramétereken keresztül – Entry: formális paraméterek – Hívás: aktuális paraméterek n A kommunikáció kétirányú lehet, a paraméterek módja szerint (in, out, in out) n Az alprogramok hívására hasonlít a mechanizmus (fontos különbségek!)
58 Várakozási sor n Egy entry-re több fiú is várhat egyszerre n De a lány egyszerre csak eggyel randevúzik n Egy entry nem olyan, mint egy alprogram, mert nem „re-entráns” n A hívó fiúk bekerülnek egy várakozási sorba n Minden entry-nek saját várakozási sora van n Ha a hívott lány egy accept utasításhoz ér, a legrégebben várakozóval randevúzik (vagy, ha nincs várakozó, akkor maga kezd várni)
59 A belépési pontok n Minden belépési ponthoz tartoznia kell legalább egy accept utasításnak a törzsben n Akár több accept utasítás is lehet a törzs különböző pontjain elhelyezve n (Egy hívóban több entry-hívás is lehet) n Az entry várakozási sorának aktuális hossza: ‘Count attribútum Randi’Count
60 task Tároló is entry Betesz( C: in Character ); entry Kivesz( C: out Character ); end Tároló; Több belépési pont is lehet
61 task body Tároló is Ch: Character; begin loop accept Betesz( C: in Character ) do Ch := C; end Betesz; accept Kivesz( C: out Character ) do C := Ch; end Kivesz; end loop; end Tároló; Egyelemű buffer
62 task body T is Ch: Character; begin... Get(Ch); Tároló.Betesz(Ch);... Tároló.Kivesz(Ch); Put(Ch);... end T; Így használhatjuk
63 Aszinkron kommunikáció task body A is Ch: Character; begin... Get(Ch); Tároló.Betesz(Ch);... end A; task body B is Ch: Character; begin... Tároló.Kivesz(Ch); Put(Ch);... end B;
64 Szinkronizációs feladatok n Bizonyos erőforrásokat nem szabad konkurrensen használni n Biztosítsuk, hogy egyszerre csak egy taszk használja n Kritikus szakasz, kölcsönös kizárás n Szemafor, monitor, író/olvasó, termelő/fogyasztó, evő és ivó filozófusok
65 Kritikus szakasz n Critical section n Egy tevékenységsorozat a taszkon belül – Például bizonyos erőforrások használata n Garantáljuk, hogy egyszerre csak egy taszk van a kritikus szakaszában n Olyan, mint amikor egy sínszakaszt védünk attól, hogy több vonat is ráhajtson n Egy megoldás: szemafor
66 Szemafor n E.W. Dijkstra, 1968 n Belépés a kritikus szakaszba, ha a P művelet megengedi n Kilépéskor a V művelettel a szemafort szabadra állítjuk n P = passeren (áthaladni) V = vrijmaken (szabaddá tenni)
kritikus szakasz előtti utasítások Szemafor.P; -- blokkol: megvárjuk, amíg beenged kritikus szakasz utasításai Szemafor.V; kritikus szakaszok közötti utasítások Szemafor.P;...-- kritikus szakasz utasításai Szemafor.V; kritikus szakasz utáni utasítások Szemaforral védett kritikus szakaszok
68 Blokkoló utasítás n A szemafor P művelete felfüggeszti a hívó folyamatot, amíg az út szabaddá nem válik n A hívó folyamat blokkolódik, vár a P hívás befejeződésére n Az Ada implementációban ezt egy randevúval írhatjuk le a legkényelmesebben
69 task Szemafor is entry P; entry V; end Szemafor; task body Szemafor is begin loop accept P; accept V; end loop; end Szemafor; Szemafor Ada taszkkal megvalósítva
70 Probléma a szemaforral n A szemafor nagyon alacsony absztrakciós szintű eszköz n Könnyű elrontani a használatát n Akár a P, akár a V művelet meghívását felejtjük el, a program megbolondul n Nem lokalizált a kód, sok helyen kell odafigyeléssel használni
71 Kölcsönös kizárás n A szemafor segítségével kritikus szakaszokat tudunk leprogramozni n Csak egy folyamat tartózkodhat a kritikus szakaszában n A kritikus szakaszra (a kritikus erőforráshoz való hozzáférésre) kölcsönös kizárást (mutual exclusion) biztosítottunk
72 Monitor n C.A.R. Hoare, 1974 n Egy másik eszköz a kölcsönös kizárás biztosítására n Sokkal magasabb szintű, mint a szemafor n Az objektum-elvű szemlélethez illeszkedik n A kritikus adatokhoz való hozzáférés csak a szinkronizált műveleteken keresztül – egységbe zárás (encapsulation) – adatelrejtés n Megvalósítás: feltételváltozó, wait, signal n Java
73 Egy monitor Ada taszkkal task Kizáró is entry Kiír( Str: String ); end Kizáró; task body Kizáró is begin loop accept Kiír(Str: String) do Ada.Text_IO.Put_Line(Str); end Kiír; end loop; end Kizáró; kritikus tevékenység
74 Monitorok és az Ada n Ha nem csak egy művelete van? – select utasítás – Bonyolultabb implementáció... n Van speciális nyelvi elem, amivel még könnyebb ilyeneket csinálni: védett egységek n A kölcsönös kizárásnál megengedőbb szinkronizáció? – író-olvasó feladat? – evő vagy ivó filozófusok?
75 Monitor versus Szemafor n A monitor magasabb szintű eszköz n A szemaforokkal rugalmasabban készíthetők kritikus szakaszok – nem kell előre elkészíteni az összes kritikus szakaszt – több kritikus erőforrás használatát könnyebb kombinálni egy kritikus szakaszon belül
76 Kivételek n Taszkok törzse is tartalmazhat kivételkezelő részt n Taszkokkal kapcsolatos predefinit kivétel Tasking_Error n Ha a főprogramot kivétel állítja le: kiíródik n Ha más taszkot kivétel állít le: csendben elhal
77 Mikor hol? n Ha kivétel lép fel taszk indításakor, akkor a szülőjében Tasking_Error váltódik ki – deklarációs: a szülő begin-je után közvetlenül – allokátoros: az allokátor kiértékelésének helyszínén n Ha komplett/abnormális/terminált taszk belépési pontját hívjuk, a hívóban Tasking_Error váltódik ki a hívás helyszínén n Ha egy randevú kivétellel zárul, akkor a kivétel mindkét randevúzó félre átterjed