A processzek általában független entitások, melyek egy párhuzamos rendszer különböző ágenseit reprezentálják. Függetlenek olyan értelemben, hogy mindegyik tartalmazza a megfelelő adatokat saját feladatának végrehajtásához. Elvárjuk továbbá tőlük, hogy teljesítsék a modularitás következő három szabályát:
Az OCCAM esetében egy processz más processzek kompozíciója, primitív processzekből egyre összetettebb processzek épülnek. Általában a következőképp néz ki egy processz:
A <Declarations> részben a processz által használt változókat deklaráljuk, a <Process.Body> rész a processz végrehajtható részét definiálja.
A legegyszerűbb processz egy programban a tevékenység (action), ami lehet értékadás, input és output.
A CCS és CSP féle nyelveknél az egyszerű (primitív) processzek mint egyszerű műveletek, processzek által elvégezhető események vannak jelen. Ezek atomi műveletek, az előző processz felfogás szerint igazán nem is processzek.
A SKIP egy nullprocessz. Elindul, nem csinál semmit, majd terminál. Különböző fajta strukturált eljárások írásakor hasznos.
A STOP is nullprocessz, mint a SKIP, de szemben a SKIP-pel, a STOP egy "elromlott" processzt eredményez. Hasznos akkor, ha egy hiba fellépése után ezzel állítunk meg egy processzt, így megakadályozva a hiba esetleges továbbterjedését.
Ez a process hasonló, mint más nyelvek értékadó utasításai, de az OCCAM-ban lehetőségünk van párhuzamos értékadásra is, vagyis több változóhoz egy időben rendelni hozzá értékeket. Pl.:
Ekkor x és y értéke kicserélődik. A párhuzamos értékadások mindig ugyanarra az eredményre vezetnek, mintha a jobb oldali kifejezéseket sorra kiértékelnénk, majd ezután hozzárendelnénk rendre a bal oldali változókhoz. A kifejezések és változók száma meg kell, hogy egyezzen, tehát pl. a
értékadás hibás.
Két kommunikációra használt primitív processz áll rendelkezésre.
Nagyobb processzeket az egyszerű processzekből készíthetünk adott konstrukciós eszközökkel, melyek a következőek lehetnek:
SEQ |
szekvencia |
IF |
feltétel |
CASE |
szelekció |
PAR |
párhuzamos végrehajtás |
ALT |
alternation |
A szekvenciában az egyik processz befejezése után indul a következő. A szekvencia áll a SEQ kulcsszóból és nulla vagy több processz felsorolásából, két szóköznyi bekezdéssel.
Pl.:
Ez két szekvenciálisan végrehajtott processzben bekér egy karaktert a keyboard csatornáról majd kiírja azt a screen csatornára.
A konstrukciók egymásba ágyazhatók, mint pl.:
Ismételt szekvenciát használhatunk, ha indítani akarunk megegyező processzeket szekvenciálisan, és indításkor ismerjük a processzek számát. Pl.:
A feltétel tetszőleges számú processzből és hozzájuk tartozó feltételekből áll. Végrehajtáskor sorban megy végig a feltételeken, és amely feltétel igaz, ahhoz tartozó processzt végrehajtja, majd terminál. Ha egyik feltétel sem igaz, akkor a feltétel működése megegyezik a STOP elemi processzével. Pl.:
A feltételt ugyanúgy lehet ismételni, mint a szekvenciát. Pl.: (két sztring összehasonlítása)
Adott egy kifejezés majd felsorolva a szelektorok, a szelektorokhoz processzek rendelve. Amelyik szelektor értéket a kifejezés felveszi, az az ág hajtódik végre, ha nincs ilyen, működése megegyezik a STOP-éval. Lehetőség van ELSE ág megadására, amely akkor hajtódik végre, ha egyik más ág sem. Pl.:
A while ciklus addig ismétel egy processzt, míg a feltétele igaz. Pl.:
A PAR szerkezet valahány processzt tartalmaz, melyek végrehajtása párhuzamosan történik. Áll a PAR kulcsszóból, ,majd a processzek listájából, két szóközzel bentebb kezdve. A párhuzamosítás beágyazható önmagába, így létre lehet hozni a processzek egy hiearchikus szerkezetét. Pl.:
Megszorítások változók és csatornák párhuzamos használatára (a kölcsönös kizárás biztosítására):
A párhuzamosítást ugyanúgy ismételtethetjük, mint a szekvenciát és a feltételt. Pl.:
Az alternatív végrehajtás tetszőleges számú processzből áll, melyekhez tartozik egy-egy őrfeltétel. Ezek közül csak egy hajtódik végre, valamelyik azok közül, ahol az őrfeltétel igaz, hogy melyik, azt a nyelv nem definiálja. Az őrfeltételben használható a csatornára való írás és csatornáról olvasás művelete. Ez akkor lesz igaz értékű, ha a művelet sikeres. Ha nincs egy ilyen ág sem az alternációban, akkor a végrehajtás szünetel addig, amíg valamelyik igaz nem lesz. & jellel lehet összekapcsolni több őrfeltételt.
Pl.: Itt a csatornáról olvasás nem is történik meg, ha left.enabled hamis.
Hasonlóképp, mint az előzőek.
Lehetőségünk van prioritást rendelni az alternatív végrehajtás processzeihez a PRI ALT kulcsszóval. Ekkor a forrásban felvett sorrendjüknek megfelelően csökken a prioritásuk. Amennyiben több processz őrfeltétele is igaz, a nagyobb prioritású (előbb lévő) hajtódik végre. Pl.:
Az OCCAM prcesszek változókkal működnek, csatornák és timer-ek (időzítők) segítségével kommunikálnak. A változó rendelkezik egy értékkel, új értéket kaphat egy értékadásból vagy egy csatornáról mint input. A csatornák értékeket közvetítenek. Az időzítők előállítanak egy értéket, mely az időt reprezentálják.
A kommunikációs csatorna valamely értékek nem pufferelt, point-to-point szállítását teszi lehetővé konkurens processzek közt. Ezen értékek formátumát és típusát az ún. protokoll írja le. A csatorna neve és a protokoll alkotják a csatorna deklarációját. A CHAN OF kulcsszót követi a protokoll. A csatorna típust nem lehet elnevezni, a protokollt viszont igen.
A csatorna típusa:
A csatornákat hasonlóképp deklaráljuk mint a változókat, még tömböket is képezhetünk belőlük, használhatjuk a komponenseket és szegmenseket is.
Protokollokat külön elnevezhetünk a következőképp:
A legegyszerűbb protokollok csak egy típusnévből állnak. Pl.:
Ezzel lehetőségünk nyílik előre nem ismert hosszúságú tömbök kommunikálására a csatornán keresztül. Megkapjuk a tömb méretét és méretnyi elemet. Pl.:
A szekvenciális protokoll egyszerű protokollok kommunikációjának egymásutánja. Pl.:
A CASE protokoll lehetővé teszi különböző formájú üzenetek kommunikációját egy csatornán kereszül. Pl.:
Néha szükséges lehet, hogy olyan csatornát definiáljunk, ahol valamilyen oknál fogva a protokoll formátuma nem ismert. Erre jó az anarchikus protokoll. Erre használható az ANY kulcsszó. Pl.:
Ebben az esetben a csatornára csak írni és olvasni lehet, nem használható összetett protokoll. A küldött és fogadott adatok mint bájtsorozat kezeljük. Csatornára írást a ! jel, olvasást a ? jel szolgálja.
Az Occam 3-ban lehetőségünk van távolról hívható csatornatípus (remote call channel) definiálására. Ezeknek segítségével érhetünk el egy másik gépen futó szolgáltatást, adatbázist vagy egyebet. A távoli eljáráshíváshoz a két gép között point-to-point kapcsolatra van szülkség. Alapvetően ugyanúgy működik, mint egy helyi eljáráshívás, de több megkötés és szintaktikai különbség van köztük:
Kétféle paramétere lehet:
Távoli eljárást deklarálni kell a hívó félnél (pontosabban: hívható csatorna deklarálása): Pl.:
A szerverben pedig definiálni kell a hívást fogadó eljárást: Pl.:
És a hívása pedig ugyanúgy történik, ahogy a normál eljáráshívás: Pl.:
Osztott hívható csatornát hasonlóan lehet deklarálni, mint a szokásos csatornákat, csak egy SHARED kulcsszó kell elé. Pl.:
Az így deklarált hívható csatornát meg lehet osztani több processz között. A megosztott csatorna használat megegyezik a meg nem osztottéval. A fogadó processz nem fogad el többet egy hívásnál ugyanabban az időben.
Osztott kommunikációs csatornát hasonlóan lehet deklarálni, mint a szokásos csatornákat, csak egy SHARED kulcsszó kell elé. Pl:
Az osztott csatorna használata: ahhoz, hogy hozzá tudjunk férni egy osztott kommunikációs csatornához az elosztott végén, előbb hozzáférési jogot kell hozzá igényelnünk a CLAIM kulcsszóval. Ezek után a CLAIM blokkon belül ugyanúgy használhatjuk a csatornát, mintha nem lenne osztott. Pl.:
Ha a nem megosztott végét akarjuk használni a csatornának, akkor ezt a végét a GRANT kulcsszóval ki kell sajátítani a processzünk számára, és ezek után ezt a csatornát már rajtunk kívül senki más nem használhatja.
Osztott hívható csatornákat is lehet Osztott kommunikációs csatornákkal szimulálni (Lásd előző példa).
A nyelv szinkronizációs eszközöket nem szolgáltat, lévén csak az üzenetküldés párhuzamos programozási modellt támogatja. A processzek szinkronizációja a kommunikációval és a timer-eken keresztül valósul meg. Ez azt jelenti, hogy a csatornát író processz blokkolódik addig, amíg az írást nem tudja elvégezni (még van a csatornán elem), az olvasó processz pedig addig, amíg olvasni nem tud (nincs rajta elem).
A timer egy speciális csatorna, ahonnan a rendszeróra olvasható le. A timert mint változót deklaráljuk, majd az óra értékének fogadására egy integer változót használunk. Példa:
Az AFTER kifejezés használatával lehetőségünk nyílik timeout processzek írására. Példa:
Ekkor a futtató process végrehajtása felfüggesztődik addig, míg a clock rendszeridő a time utánira nem nő. A kifejezésnek az AFTER után egészértékűnek kell lennie.
Occam 3-ban lehetőségünk van interface-eket definiálni, és ezáltal elrejteni a reprezentációt a felhasználók elől. Ez a funkció alapvetően a távolról hívható csatornákra épül. Pl.:
Itt deklaráltunk két hívható csatornát a Put-ot és a Get-et mint interface-t, amelyek implementálják a cache-t.
Az előző pontban láthattuk, hogy egy logikai egységhez hogyan rendelhetünk hozzá egy korlátozott interface-t. Ebben a pontban megmutatjuk, hogy hogyan tudunk definiálni több elnevezett modul-t hasonló implementációval. Pl.:
És ebből a modul típusból tudunk létrehozni példányokat. Pl.:
Vagy akár tömbbe is pakolhatjuk a létrehozott modulokat:
Ez a deklaráció ekvivalens a következőkkel:
Itt minden egyes tömbelemnek ugyanaz az interface-e, noha nem ugyanaz a típusuk.
A párhuzamos komponensek mindegyike egy egyedi processzoron fut. A nyelv ebben az esetben lehetőséget ad rá, hogy mi döntsük el, hogy melyik processz melyik processzoron fusson. Ennek megadására használható a PLACED kulcsszó. Pl.:
A processzorok megadása számozással történhet, mint ahogy ez a példában is látszik.
Ha csak egy processzor áll rendelkezésünkre, akkor is tudjuk futtatni az ekkor kvázi párhuzamos programjainkat, és ehhez kapunk egy újabb nyelvi elemet, amellyel meghatározhatjuk a processzek prioritását. A prioritást a processzek sorrendje alapján állítjuk fel, és a legelső processz-nek lesz a legnagyobb a prioritása. Az egymást követő processzek egyre csökkenő prioritást kapnak, és a legutolsó processz pedig csak kerül végrehajtásra, ha az összes előtte lévő folyamat már befejeződött. Ennek megadására a PRI kulcsszó. Pl.: