Concurrent Pascal
Lexikai elemek
Milyen karakterek használhatóak a nyelvben?
nem definiált, de tartalmaznia kell:
- betűk 'a',...,'z','A',...,'Z'
- számjegyek '0',...,'9'
- szóköz, tabulátor
- sorvége szimbólum (implementációfüggő)
- ()[]{}+-*/:;,.<>=!?#%'
Milyen karakterek használhatóak azonosítók leírására, mi az azonosítók szintaxisa?
betűk, számjegyek, aláhúzás, de nem kezdődhet aláhúzással
megkülönbözteti-e a kis- és nagybetűket?
van-e hosszúsági megkötés az azonosítókra?
kötött szavak:
accept, and, array, at, begin, case, channel, cobegin, coend, const, div, do, else, end, entry, export, for, forever, forward, function, guarded, if, in, mod, monitor, not, null, of, offset, or, pri, procedure, process, program, provides, record, repeat, replicate, requeue, resource, select, terminate, then, timeout, to, type, until, var, when, while
van-e különbség a kulcsszavak, és az előre definiált szavak között?
literálok:
numerikus literálok:
- egész (shortint, integer, longint, byte, word)
- valós (real, single, double, extended, comp)
- bővebben lásd: itt
megengedett számrendszerek:
- bármilyen (#)
- tizes
- hexa ($)
stringliterál
- Concurent Pascal-ban nincs string típus
megjegyzések (komment)
- csak blok komment van ((*...*), {...}), melyek nem ágyazhatók egymásba
- bővebben lásd: itt
Beépített adattípusok
a műveletek a típushoz tartoznak-e?
csak a típusértékhalmaz, mivel a műveletek nem tartoznak a típushoz, kivéve néhány alaptípuson értelmezett műveletet (pl.: felsorolás: ord(...), pred(...))
mik a beépített adattípusok?
az alap Pascal adattípusokon kívül (kivéve string): Process, semaphore, monitor, resource, channel, channel of synchronous, bitset, condition
szigorúan típusos-e a nyelv?
igen, mivel fordítási időben meghatározható típussal kell rendelkeznie minden kifejezésnek.
elemi típusok, összetett típusok?
egyéni jellemzők:
csatorna lehet szinkron (channel of synchronous)
felsorolási típusoknak képezhető résztartománya, melyre beállítható a határok figyelése
rendezett típusok:
- a kezdő- és végérték tetszőlegesen megadható
- tömbők lehetnek többdimenziósak is
- a logikai típus a felsorolási típusba tartozik
altípusdefiniálás:
nem lehet altípust definiálni
egész oszás, hatványozás:
egész osztás van (mod(...), div(...) /a '/' mindíg valóssal tér vissza/), egész hatványozás nincs (legfeljebb csak felhasználó által definiált eljárással)
egész, valós típusok értékét a definíció, vagy az implementáció korlátozza?
mindkettőt expilicit meghatározza a nyelv definíciója
vannak-e típus nélküli pointerek?
mutatóaritmetika:
- pointerre aritmetikai kifejezések az összehasonlításon kívül nem értelmezettek
- bármely változó címe értékül adható tetszőleges típusra mutató pointernek
- egyenlőségvizsgálat: pointerek egyenlőségének vizsgálata (nem az általuk hivatkozott objektumoké)
dereference:
szemétgyűjtés:
a mutatók által lefoglalt memóriaterületet manuálisan kell felszabadítani a freemem(...) eljárással
érvénytelen pointerre hivatkozás:
nem nil pointerre való hivatkozás megengedett, még akkor, is, ha a pointer már érvénytelen területre mutat
aoutomatikus változóra pointer hivatkozás:
- pointer absolute típusdeklarációval
- futás közben az Addr(...) függvénnyel
automatikus típuskonverzió:
csak kisebb helyfoglaláskor nagyobbra áttéréskor, ez is csak azonos főtípusba eső típusnál
típus kezdeti értéke:
több mutató egy objektumra:
új típus definiálása:
- tömb típus
- indexe lehet bármilyen felsorolási típus
- eleme lehet bármilyen típus
- határellenőrzés bekapcsolható
- méretmeghatározás, helyfoglalás deklarációkor
- több dimenzió megengedett
- egyben értékadás nem megengedett
- altömb képzés nem megengedett
- tömbkonstans deklarálható
- rekord típus
- kiválasztás: <rekord>.<mezőnév>
- egyben értékadás nem megengedett
- rekord konstans deklarálható
- unió típus
- nincs külön unió típus, de megoldható rekord típussal
Változók, kifejezések
Utasítások, vezérlési szerkezetek
- az alábbiakban nem felsoroltakat lásd: itt
- az utasítások egyszerű utastások, azaz nincs értékük
- többszörös értékadás nem megengedett
- üres utasítást nem kötelező kiírni (null kulcsszó)
- nincs eseményvezérelt programozás megvalósítva
- a szekvenciát jelző ';' kiírása kötelező, szerepe utasítás lezáró
- utasítás lehet blokkutasítás is, melyben elhelyezhető újabb deklaráció (a hatásköre a blokkutasítás)
- elágazás:
- feltételes egyirányú elágazás: if () then ;
- kétirányú elágazás: if () then else ; (az else a legutosó if-hez tartozik)
- többirányú elágazás: case of {:} end;
- a szelektortípusa bármilyen felsorolás típus lehet
- nem kell elfedni a szelektor lehetséges értékeit, és nem lefedett érték üres utasítást eredményez
- egy ág végrehajtása után a vezérlés a case után folyatódik
- egy érték csak egyszer szerepelhet a feltételek között
- a feltétel lehet egy érték, felsorolás ','-vel elválasztva vagy intervallum ([..])
- ciklus:
- nem ismert lépésszámú ciklusok:
- while () do ; (elöltesztelő)
- repeat until ; (hátultesztelő)
- elöltesztelő ciklusnál a feltétel a bentmaradás feltétele (while true do ...; - végtelen ciklus)
- hátultesztelő ciklusnál a feltétel a kilépés feltétele (repeat ... until false; - végtelen ciklus)
- a feltétel logikai típus kell legyen
- az elöltesztelő ciklus magja egy utasítás lehet (esetleg blokk utasítás)
- a hátultesztelő ciklus magja több utasítás lehet (új blokk kezdődik)
- előre ismert lépésszámú ciklusok:
- for = to do ;
- for = downto do ;
- a ciklusváltozó felsorolási típusú kell legyen
- nem változtatható a ciklusváltozó alsó, felső határa
- a lépésköz to esetén pred(...), downto esetén succ(...)
- a ciklusváltozót a ciklusmagon belül nem lehet változtatni
- a ciklusváltozó értéke a ciklus után a végérték (to esetén a felső, downto esetén az alsó határ)
- általános ciklus: repeat forever;
- iterátor csak felsorolási típusra létezik (pred(...) - megelőző, succ (...) - következő)
Alprogramok
- paraméterátadás módja lehet: érték, cím szerint
- eljárás (procedure): nincs visszatérési értéke (parancs)
- függvény (function): van visszatérési értéke, de nem tekinthető lekérdezésnek, mert lehet érték-eredmény szerinti formális paramétere
- a formális paramétereknek nincs alapértelmezett értékük
- a programnevek, operátorok nem átlapolhatók
- új operátorok nem definiálhatók
- nincs típussal való paraméterezhetőség
- paraméter lehet alprogram címe
- bővebben lásd még: itt
Sablonok
A Concurrent Pascal nem támogatja a sablonokat (generic).
Kivételkezelés
A Concurrent Pascal nem támogatja a kivételkezelést (exception handling).
Helyességbizonyítás
A Concurrent Pascal nem támogatja a helyességbizonyítást.
Objektum-orientáltság
A Concurrent Pascal nem támogatja az objektumorientált programfejlesztést (OOP)
A párhuzamosságot támogató nyelvi eszközök
- a párhuzamosságot a nyelv támogatja (még párhuzamos hardware nélkül is, mivel saját ütemezője van)
- a párhuzamosság kijelölése: cobegin coend;
- nincs processen belüli process (azaz már párhuzamosan futtatott szálból nem indítható újabb szál, csak a főszálból)
- a processek használhatnak osztott változókat
- kommunikációs modellek:
- aszinkron kommunikáció üzenetekkel:
- szinkron kommunikáció
- szinkron csatorna
- ada típusú randevú
- kölcsönös kizárás
- szemafor, megengedett műveletei:
- wait(...) - várakozás a szemaforra
- signal(...) - a szemafor elengedése
- initial(...) - kezdeti érték beállítása
- write(...), writeln(...)
- monitor:
- export: kívülről csak ezen eljárások hívhatóak meg
- condition: a monitor belső várakozási sorai (típus)
- delay(): beáll a várakozási sorba
- resume(): beenged egy a -ön várakozó folyamatot a monitor kizárólagos használatára
- empty(): igaz, ha üres a
- erőforrás:
- export: kívülről csak ezen eljárások hívhatóak meg
- guarded procedure (...) when : ha a igaz, akkor az eljárás meghívható, ellenkező esetben az eljáráshívás felfüggesztődik az eljárás várakozási során
- a párhuzamos futás végetér, ha
- minden szál befejeződik
- valamelyik szál futásidejű hibát okoz
- a szálak holtponthelyzetbe kerülnek
A cobegin, coend pár között felsorolt utasítások, alprogramok egyszerre kapnak jogot a futásra. A végrehajtás sorrendjét minden esetben a beépített ütemező szabja meg, melynek kétféle "viselkedése" lehet, melyek futtatáskor állíthatóak: Korrekt (Fair), és Nem korrekt (Unfair) ütemezés. Korrekt ütemezésnél egy véletlenszám generátor alapján generálja, hogy mely szálak kaphatják meg a vezérlést. Nem korrekt ütemezésnél a végrehajtó környezet úgy tekinti, mintha a cobegin, coend pár helyett begin, end pár állna. Az előzőek értelmében nyilvánvaló, hogy a fordító nem valódi (az adott operációs rendszeren) futtatható kódot állít elő, hanem egy pszeudo-kódot, melynek végrehajtásához szükséges a Concurrent Pascal környezete (a dolog hasonlóan működik, mint a Java-ban). Ha a párhuzamosan futó szálak mindegyike blokkolt állapotba kerül (ez történik Nem korrekt ütemezés esetén, ha bármely folyamat blokkolódik), a futtató környezet holtpontra hivatkozó hibajelzéssel leállítja a program futását. Sajnos az éheztetést (Livelock), amikor minden folyamat működik, csak éppen a működésnek nincs eredménye - pl.: üres végtelen ciklusok párhuzamosan elindítva -, nem érzékeli, így a program futását nem állítja le.
Szemaforok:
Kölcsönos kizárás megvalósítására szolgálnak, de alacsonyabb szinten, mint a monitorok, így sokkal könnyebb hibát elkövetni a kód írásakor. A szemaforoknak kezdőérték adható, mely azt határozza meg, hogy az őt igénybevevő folyamatok közül egyszerre hányan "mehetnek át" a szemaforon. Minden, a szemafort igénybevevő folyamat két esettel állhat szembe: 1, Még nincsen bent a kritikus szakaszban a szemafor által meghatározott maximális számú folyamat. Ekkor az aktuális folyamat átléphet a szemaforon. 2, Ellenkező esetben egy várakozási soron függesztődik fel, melyből véletlenszerűen választ a futtató környezet, hogy ki lépheti át a szemafort, ha egy - a szemafort addig aktívan használó - folyamat elhagyja a szemafort. Az esetleges hibalehetőségek: a szemaforon átjutott folyamat nem szabadítja fel a szemafort, mikor végzett. Ekkor eggyel kevesebben juthatnak csak át a továbbiakban a szemaforon. Ha az előbbi hibát túl sok folyamat követi el a program holtpont hibával leáll. A második hibalehetőség onnan adódik, hogy a szemafor fizikailag nem teszi elérhetetlenné az általa logikailag védett adatokat, így azokat bárki felhasználhatja a szemafor igénybevétele nélkül.
Monitorok:
A szemaforokhoz hasonlóan a monitorok is a kölcsönös kizárást teszik lehetővé, de az előbbieknél sokkal struktúráltabb módon. Mégpedig úgy, hogy az általuk logikailag őrzött adatok hozzáféréséhez fizikai védelmet is nyújtanak, oly módon, hogy azokat csak a monitor által kívülről is látni engedett (exportált) eljárásokon keresztül lehet elérni. A monitorokat leginkább az objektum orientált programozásban használt objektumhoz lehetne hasonlítani, mely nem aktív a párhuzamos futásban, hanem csak akkor hajtja végre az eljárásait, ha azokat kívülről meghívja egy másik (valóban futó) folyamat. Ha a párhuzamos futás alatt a monitor szolgáltatását több folyamat is szeretné igénybe venni, akkor a szemaforoknál leírt várakozási sorhoz hasonló rendszer lép életbe, azzal a különbséggel, hogy a monitor által védett adatokhoz egyszerre csak egy folyamat férhet hozzá. Fontos még, hogy míg a szemaforoknál egyszerre többet is le lehet foglalni, addig egymásba ágyazott monitorhívásokra nincs lehetőség a potenciális holtpont, és a védett adatok konzisztenzitása miatt. Még ugyanazon monitor egy másik eljárása sem hívható monitoreljárásból. Az előző egymásbaágyazási kísérletek fordítási hibát okoznak.
Erőforrások:
Ugyancsak a kölcsönös kizárás megvalósítására használhatóak, a monitorokhoz nagyon hasonló módon, ám míg ott az egy monitoron belüli egymásbaágyazott eljáráshívásokra sincs lehetőség, addig az erőforrásoknál ez speciális módon, a requeue kulcsszóval megtehető. A requeue utasítás csak őrfeltételes erőforrás eljárásban helyezhető el (lásd később). Ekkor a hívott eljárás befejeződik, és a hívott eljárás úgy hajtódik végre, mintha az lett volna az eredeti erőforráshívás, azaz a vezérlés nem a requeue-t kiadó eljáráshoz tér vissza, hanem az azt hívó eljáráshoz (esetleg ezt rekurzívan, míg olyan eljáráshoz nem jutunk, mely nem az erőforrás eljárása). Fontos, hogy egy adott erőforrásból továbbra sincs lehetőség más erőforrás eljárását hívni. Az erőforrásba való belépést a várakozási soron kívül még egy őrfeltétellel is megtoldhatjuk, mely akkor kerül kiértékelésre, ha egy folyamat túljutott a várakozási soron. Erre szolgálnak az őrfeltételes eljárások (Guarded procedure). Itt az őrfeltétel egy logikai kifejezés, mely ha igaz, akkor nem történik semmi (mintha ott sem lenne), ám ha hamis, akkor a hívás felfüggesztődik a korábban említett várakozási soron.
Aszinkron csatornák:
Előre deklarált típusú "üzeneteket" lehet velük küldeni. A deklarálás kódja: var : channel of . A küldés kódja: !, a fogadásé: ?.
Szelektív várakozás:
Ha több csatornából is akarunk olvasni, de nem tudjuk, milyen sorrendben érkeznek az adatok, és nem is lényeges, akkor alkalmazhatjuk a szelektív várakozást: select or else end. (Az or ágból több is szerepelhet, a legutolsó or vagy az else ágban lehet a csatorna olvasás helyett timeout vagy terminate utasítás, melyekről a továbbiakban lesz szó.) Ekkor a legelső végrehajtható csatorna olvasás hajtódik végre és a szelektív várakozás befejeződik, vagy várakozik, amíg nincs olvasható adat a felsorolt csatornák valamelyikén. A timeout alternatíva hatására, ha nincs olvasható adat másodpercig a felsorolt csatornákon, akkor a timeout-ot tartalmazó ág hajtódik végre. A terminate utasítás szerepe a következő: ha egyik csatornáról sem lehet adatot olvasni, és már minden más szál befejeződött, vagy terminate utasításon várakozik, akkor a program futása véget ér. Jegyezzük meg, hogy ha nincs timeout utasítás a szelektív várakozásban, egyik csatornáról sem tudunk olvasni, és minden más szál befejezte a futását, vagy blokkolódott egy szelektív várakozásban, akkor a program holtpontra utaló hibaüzenettel ér véget.
A csatornák ugyanúgy tömbbe szervezhetők, mint bármely más típus.
Szinkron csatornák:
Hasonló az aszinkron csatornákhoz, de a deklaráció a következő: : channel of synchronous. A synchronous típus előre definiált típus, de valódi értéke nem lehet. A küldés és fogadás módszere abban tér el az aszinkron csatronáknál leírtaktól, hogy küldeni és fogadni csak any-t lehet, ami ugyancsak előre definiált és nem adható értékül semmilyen tipusú változónak. Azaz a küldésnél és a fogadásnál is a helyett kötezően csak any állhat.
Szabványos könyvtárak
A nyelv nem ad lehetőséget és nem támogatja a szabványos könyvtárak használatát.