6. fejezet - Időkezelés és adatátvitel

Tartalom
6.1. Lehetetlenségi tétel (Two Generals' Problem)
6.2. Bizánci tábornokok problémája (Byzantine generals problem)
6.3. Ütemezés
6.3.1. Task tulajdonságai és az ütemezés kapcsolata
6.3.2. Ütemezők típusai
6.3.2.1. Egyszerű ütemezők
6.3.2.2. Prioritásos ütemezők
6.3.2.3. Többszintű algoritmusok
6.4. Task-ok közötti kommunikáció

Az elosztott rendszerek jellemző problémája az időkezelés. A kommunikáció véges volta miatt előfordulhat, hogy ha két csomópont egymást követő eseményéről (az esemény a rendszer-állapot detektálható, pillanatszerű változása) tájékoztatást ad két másik csomópontnak, akkor az üzenetek megérkezési sorrendje el fog térni az események időbeni sorrendjétől. Ebben az esetben a csomópont a korábban bekövetkezett eseményről később szerez tudomást. A probléma feloldásához fontos a csomópontok közti megegyezés.

Az időkezelés rendkívül fontos a valós idejű rendszerek esetében, mivel egy meghatározott időn belül el kell kezdeni az esemény feldolgozását. A követelmények szigorúsága alapján két féle valós idejű rendszert különböztethetünk meg. A „Hard real-time” rendszerek esetében szigorú követelmények vannak előírva, és a kritikus folyamatok meghatározott időn belül feldolgozásra kell, hogy kerüljenek. „Soft real-time” rendszer esetében a követelmények kevésbé szigorúak és a kritikus folyamatokat a rendszer mindössze nagyobb prioritással dolgozza fel.

6.1. Lehetetlenségi tétel (Two Generals' Problem)

A biztonságos üzenetküldés és kommunikáció alapvető követelménye, hogy a küldő meggyőződjön arról, hogy az elküldött üzenetet a vevő fél megkapta, vagyis mindkét fél biztos legyen abban, hogy egy adott művelet végrehajtódott. Itt a veszélyt az jelenti, ha manipuláció vagy hibás átvitel eredményeként az egyik fél úgy gondolja, hogy a művelet sikeresen végbement. A probléma az, hogy hogyan tud a művelet sikeréről meggyőződni a küldő fél. Látszólagos egyszerűsége ellenére ezt a követelményt nehéz biztosítani.

„Szövetség a völgy felett” (Two Generals' Problem) probléma a megegyezés nehézségét szemléleti. A gondolatkísérlet célja, hogy bemutassa a buktatókat és a tervezési nehézségeket egy koordinált akció megszervezésénél, ha a kommunikációt megbízhatatlan csatornán kell bonyolítani. Egy völgyben táborozott 5000 frankus katona, míg a völgy két oldalán a 3-3 ezer burkus és bergengóc katona. Burkus király (A1) és Bergengóc király (A2) szövetségesek, egyszerre akarják megtámadni a völgyben táborozó frankusokat, ezért burkus király hírnököt küld az ellenség táborán át, hogy „holnap négykor támadunk”.

A két szövetséges hadvezér csak futárok segítésével az ellenséges vonalakon keresztül tud kommunikálni egymással. A futárokat azonban elfoghatja az ellenség, így nem biztos, hogy az üzenet megérkezik. A kérdés az, hogy megoldható-e valamilyen kommunikációs módszerrel az, hogy a két hadvezér meg tud-e egyezni a támadás időpontjában. Ha A1 csomópont üzenetet küld A2-nek, az üzenet megérkezik, de A2 nem lehet biztos benne, hogy A1 tud az üzenet sikeres megérkezéséről, ezért küld egy nyugtázó üzenetet. Ezt A1 megkapja, de ő sem lehet benne biztos, hogy A2 tud a nyugtázó üzenet sikeres megérkezéséről. Így a végtelenségig lehetne hírnököket küldözgetni a két tábor között, de úgysem lenne 100%, hogy mind a két oldal biztos arról, hogy megegyeztek... [ 6.1. ábra ]

Két tábornok problémája
6.1. ábra - Két tábornok problémája


Két tábornok problémája animáción bemutatva
6.2. ábra - Két tábornok problémája animáción bemutatva


Indirekt bizonyítással és teljes indukcióval egyszerűen belátható, hogy ilyen megoldás nem létezik. Tételezzük fel, hogy véges „n” lépésben („n” darab futár küldése után) meg tudnak egyezni a hadvezérek. Ekkor viszont az „n”-edik lépésben küldött futár elfogásának esetén arra a következtetésre kellene jutnunk, hogy már az (n-1)-ik lépésben is tudniuk kellett volna a hadvezéreknek a támadás időpontjáról. Véges lépésben ellentmondásra jutunk, ha az (n-1)-ik lépésre ugyanezt a gondolatmenetet alkalmazzuk. Ez azt jelenti, hogy az első futár küldésekor tudni kellett volna a támadás időpontját. A kiindulási helyzet viszont az volt, hogy nem tudják a hadvezérek a támadás időpontját.

A történelmi példa alapján láthatjuk, hogy a legrosszabb esetet feltételező üzenetvesztés esetén nem létezik olyan biztonságos nyugtázott üzenetküldés, amely során mindkét fél meggyőződhet arról, hogy egy egyeztetés sikeres volt. Ha valamilyen természetes, nem rosszindulatú üzenetvesztést tételezünk fel (például az átviteli csatornán lévő zaj miatt), akkor az üzenet továbbításának sikerességét valamekkora valószínűséggel jellemezhetjük.

Abban az esetben, ha egy üzenetküldés biztonságos nyugtázását valamilyen valószínűséggel meg tudjuk oldani, akkor az a gyakorlatban biztonságosan megoldható probléma.

Ha rosszindulatú, intelligens támadást feltételezünk, akkor a támadó az üzenet egyeztetésének módszerét is ismeri. Ebben az esetben a Bizánci problémánál látott bizonyítás alapján egy támadó bármely kifinomult protokoll esetén elnyelhet bizonyos üzeneteket. Így valamelyik felet kétségek között tudja tartani. Ebben az esetben nem létezik elméleti és nem létezik gyakorlati megoldás sem. Ez a probléma csak mindkettő fél által hitelesített harmadik fél bevonásával oldható meg. Ha a kommunikáció nem 100%-ig biztos, akkor lehetetlen a 100%-os megegyezés.

Lehetetlenségi tétel: Véges meghibásodású csatornáról nem lehet hibátlan kommunikációt feltételezni.

6.2. Bizánci tábornokok problémája (Byzantine generals problem)

Bizonyos biztonságkritikus rendszereknél több érzékelőt, vezérlőt, esetleg több számítógépet használnak ugyanannak a jelnek a mérésére, a folyamatok vezérlésére. Erre a redundanciára azért van szükség, hogy egy részegység meghibásodása esetén is működőképes maradjon a rendszer. A probléma akkor keletkezik, ha egy rendszernél egy érzékelő teljesen más értéket mér, vagy egy vezérlő máshogyan dönt, mint a többi.

A probléma bemutatására a bizánci tábornokok problémáját használják, mely így hangzik: N tábornok táborozik a seregeivel (1000, 2000, 3000 és 4000 fős seregek) egy város körül, amit meg akarnak ostromolni. (A várost 5000 fős sereg védi.) Tudják, hogy elég sokan vannak ahhoz, hogy ha az összesített haderejüknek legalább a felével sikerül egyszerre támadniuk, akkor győzni fognak. Ha azonban nem sikerül pontosan koordinálniuk a támadás időpontját, akkor szétszóródnak a seregeik, és csatát veszítenek. Sejtik továbbá azt is, hogy vannak köztük árulók is, akik hamis üzeneteket küldenek majd. Mivel csak futárok útján tudnak kommunikálni egymással, így nem tudják ellenőrizni az egyes üzenetek hitelességét. Hogyan egyezhet meg a közös támadás időpontjáról egy ilyen nagy csoport egy bizalmas központi hatóság nélkül – főleg akkor, ha még zavarkeltő árulókkal is meg kell küzdeniük?

Az adatok alapján látszik, hogy a támadó seregek csak összefogással győzhetik le a várost védőket. Jelen esetben tehát az adat érvényességével van a baj, nem a kommunikációval.

Tábornok 3 az áruló
6.3. ábra - Tábornok 3 az áruló


Tábornok 1 az áruló
6.4. ábra - Tábornok 1 az áruló


Mindegyik csomópont (tábornok) elküldi a többieknek, hogy mennyi katonája van. Feltételezzük, hogy a 3-as hazudik, minden üzenetben mást mond [ 6.3. ábra ],[ 6.4. ábra ], jelöljük ezeket x, y, z-vel. Az egyes csomópontok a következő üzeneteket kapták:

1. (1, 2, x, 4), 2. (1, 2, y, 4), 3. (1, 2, 3, 4), 4. (1, 2, z, 4)

Ezután elküldik egymásnak a kapott üzeneteket, 3-as ismét mindenkinek mást hazudik:

1. a következő üzeneteket kapja: (1, 2, y, 4), (a, b, c, d), (1, 2, z, 4)

2. a következő üzeneteket kapja: (1, 2, x, 4), (e, f, g, h), (1, 2, z, 4)

4. a következő üzeneteket kapja: (1, 2, x, 4), (1, 2, y, 4), (i, j, k, l)

Így már kiszűrhető, hogy 1000 + 2000 + 4000 = 7000 katona biztosan van, tehát megkezdhetik a támadást. A helyes döntés meghozatalához „m” megbízhatatlan egység esetén 3m+1 iterációra van szükség. Ez a szabály a redundáns rendszerek esetében is használható.

A Bitcoin megoldást ad erre a problémára, a közmegegyezés kialakításának egyik legnagyobb kihívására. A Bitcoin megoldása a következő: minden tábornok elkezd dolgozni egy olyan matematikai probléma megoldásán, ami statisztikailag 10 percet vesz igénybe akkor, ha mindannyian munkálkodnak rajta. Amint az egyikük megtalálja a megoldást, nyomban elküldi azt az összes többinek is. Ezt követően mindenki ezzel a megoldással dolgozik tovább, ebből kiindulva keresi a következő megoldást, ami megint csak tíz percet vesz igénybe. Minden tábornok mindig az általa ismert leghosszabb megoldássorozattal dolgozik, azt bővítve tovább. Ha pedig már van egy 12-szeresen kibővített megoldásuk, akkor mindannyian teljesen biztosak lehetnek benne, hogy egyetlen áruló sem hozhatott létre sehogyan sem egy ilyen hosszú megoldássorozatot anélkül, hogy ne rendelkezne mindannyiuk összesített számítókapacitásának legalább a felével. A 12 blokkos lánc léte minden résztvevő számára egyértelműen bizonyítja, hogy a többségük tisztességesen kivette a részét annak a létrehozásából. Ezt nevezzük munkabizonyíték-rendszernek.

Mindez azt jelenti, hogy a vitathatatlanul hiteles közmegegyezés kialakítását a rendelkezésre álló számítási erőforrások korlátozottsága teszi lehetővé. Ahhoz, hogy sikeresen támadható legyen a rendszer, egy támadónak nagyobb számítási kapacitással kellene rendelkeznie annál, mint amennyit a tisztességes csomópontok birtokolnak együttesen.

6.3. Ütemezés

A feladatok (task) közül a valós idejű operációs rendszerek számára kritikus az ütemezés és az erőforrásokkal való helyes gazdálkodás megvalósítása. Mivel minden rendszer valamilyen periféria segítségével kommunikál a környezetével, ezért fontos e perifériáknak a valós idejű rendszer követelményeinek megfelelő módon történő kezelése. Az ütemezés és az erőforrásokkal való gazdálkodás azért kiemelt fontosságú, mert egy-egy esemény kezelésekor a válaszidő betartásához az eseményt lekezelő utasítássorozatot végre kell hajtani. Az utasítássorozat lefutása erőforrásokat igényel, melyeket az operációs rendszernek biztosítani kell. Ez úgy valósítható meg a leggyorsabban, ha az operációs rendszer folyamatosan rendelkezik szabad erőforrásokkal, melyeket oda tud adni az időkritikus folyamatoknak.

6.3.1. Task tulajdonságai és az ütemezés kapcsolata

Az ütemezés során a folyamatok két legfontosabb tulajdonsága a kritikusság és az időzítési viszonyok. Nem elég csupán az időzítési viszonyokat figyelembe venni. A kommunikációs, szinkronizációs tényezőkre, a precedenciára és a kölcsönös kizárásra is figyelni kell. Az időzítési viszonyokat az alábbi attribútumokkal írhatjuk le [ 6.5. ábra ]:

  • Ci az i-edik task végrehajtási ideje (computation time, kiszolgálási idő)

  • Di az i-edik task végrehajtásának határideje (dead time)

  • Ri az i-edik task válaszideje (response time),

  • Ti az i-edik task periódusideje, ennek letelte után futtatható a következő task

Task futásának fontosabb időpontjai
6.5. ábra - Task futásának fontosabb időpontjai


6.3.2. Ütemezők típusai

A CPU ütemezésnek különböző szintjeit tudjuk megkülönböztetni:

  • Hosszú távú (long term) ütemezés, vagy munka ütemezés

  • Középtávú (medium term) ütemezés

  • Rövidtávú (short term) ütemezés

Nem minden általános célú operációs rendszerben van mindegyik ütemezés megvalósítva. A nagy rendszerekben mind három típus jelen lehet. A kis vagy közepes rendszerekben egy, legfeljebb két ütemező van. Amikor több mint egy ütemező van, nagyon fontos az együttműködésük.

A hosszú távú ütemező a nagy erőforrás igényű alacsony prioritású folyamatokat választja ki, amit arra használhatunk, hogy az alacsony aktivitású időszakokban dolgoztassuk az erőforrásokat. A hosszú távú ütemező elsődleges célja biztosítani az alacsony prioritású folyamatok egyenletes terhelését. A hosszú távú ütemező használata rendszer-, és terhelésfüggő, de sokkal ritkább, mint a többi ütemezőé. Feladata, hogy a háttértáron várakozó, még el nem kezdett munkák közül meghatározza, hogy melyek kezdjenek futni, a munka befejezésekor ki kell választania egy új elindítandó munkát. A hosszú távú ütemezést végző algoritmusnak ezért ritkán kell futnia.

A középtávú ütemezés az időszakos terhelésingadozásokat hivatott megszüntetni, hogy a nagyobb terhelések esetében ne legyenek időtúllépések. A középtávú ütemező algoritmus ezt úgy oldja meg, hogy bizonyos (nem időkritikus) folyamatokat felfüggeszt, illetve újraaktivál a rendszer terhelésének a függvényében. Folyamat felfüggesztése esetén a folyamat a háttértáron tárolódik, az operációs rendszer elveszi az erőforrásokat, melyeket csak az újraaktiválásakor ad vissza a felfüggesztet folyamatnak.

A rövidtávú ütemezés feladata, hogy kiválassza, hogy melyik futásra kész folyamat kapja meg a CPU-t. Fő feladata maximalizálni a rendszer teljesítményét bizonyos feltételek kielégítése mellett (határidők). A rövidtávú ütemezést végző algoritmus gyakran fut le, ezért gyorsan kell lefutnia. Mivel gyakran lefut az algoritmus, ezért az operációs rendszer mindig a memóriában tartja az ütemező kódját. Az operációs rendszerek magja tartalmazza az ütemezőt.

Az általános célú és a valósidejű operációs rendszerek a CPU ütemezésben különböznek leginkább egymástól. Ennek az oka az, hogy a valósidejű operációs rendszereknek az eseményeket meghatározott időn belül le kell reagálnia, egy általános célú operációs rendszer esetében nincsenek ilyen jellegű követelmények.

Az ütemezéssel kapcsolatban a következő alapfogalmakat értelmezhetjük:

  • Task: Önálló részfeladat.

  • Job: A task-ok kisebb, rendszeresen végzett feladatai.

  • Process: A legkisebb futtatható programegység, egy önálló ütemezési entitás, amelyet az operációs rendszer önálló programként kezel. Van saját (védett) memóriaterülete, mely más folyamatok számára elérhetetlen. A task-okat folyamatokkal implementálhatjuk.

  • Thread: Saját memóriaterület nélküli ütemezési entitás, az azonos szülőfolyamathoz tartozó szálak azonos memóriaterületen dolgoznak.

  • Kernel: Az operációs rendszer alapvető eleme, amely a task-ok kezelését, az ütemezést, és a task-ok közti kommunikációt biztosítja. A kernel kódja hardver függő (device driver) és hardware független rétegekből épül fel. A hardware függő réteg új processzorra és eszközökre történő adaptálását az operációs rendszer portolásának nevezzük.

  • CPU löket (CPU burst): A folyamatnak csak CPU és az operatív tár kell

  • Periféria löket (I/O burst): Perifériás átvitelt hajt végre a folyamat, nincsen szükség CPU-ra

Folyamat állapotai ütemezés szempontjából
6.6. ábra - Folyamat állapotai ütemezés szempontjából


Megszakításos ütemező
6.7. ábra - Megszakításos ütemező

Nem megszakításos ütemező
6.8. ábra - Nem megszakításos ütemező

Ütemezés során a folyamatokkal a következő esemény következhet be:

  • A futó folyamat várakozni kényszerül (Például: I/O-ra, erőforrásra). A task egy meghatározott eseményre várakozik. (Ez rendszerint valamilyen I/O művelet szokott lenni.)

  • A futó folyamat befejeződik.

  • A futó folyamat lemond a CPU-ról.

  • A futó folyamattól az operációs rendszer elveszi a CPU-t. A task-ot megszakították, vagy a megszakítás kezelő rutin éppen megszakítja a folyamatot.

  • A folyamat aktiválódik, futásra késszé válik. A futásra kész állapotot jelöli. Fontos a task prioritási szintje és az is, hogy az éppen aktuálisan futó task milyen prioritási szinttel rendelkezik, ezek alapján dönti el az ütemező, hogy elindítja-e a taskot.

A task-ok állapotát és tulajdonságait a Task Vezérlő Blokk (Task Controll Block – TCB) írja le, amely a memóriában lévő adatszerkezet. Fontosabb tagjai a következők:

  • Task ID: Egy egész szám, amely a task-ot azonosítja.

  • Context: Program Counter: a regiszterek és flag-ek elmentett értékei. (A task futásának helyreállításához szükségesek ezek az információk.)

  • Top of Stack: Egy mutató, amely megadja a task-hoz tartozó verem tetejét

  • Status: Egy egész szám, amely utal a task aktuális státuszára.

  • Priority: A prioritás aktuális értéke, amely a futás közben megváltoztatható.

  • I/O Information: Leírja, milyen perifériákat és I/O-kat foglalt le és használ a task. A nem használt perifériákat minden esetben fel kell szabadítani.

Bármilyen ütemezési stratégiát is alkalmazzunk, a folyamatmenedzselő rendszernek a megszakítások kezelésével is kell foglalkoznia. Ezek a megszakítások lehetnek hardveresek és szoftveresek egyaránt. A megszakítás környezetváltást (context switch) követel. A futó folyamat megszakad, és a megszakítás kezelő egy gyorsan végrehajtható kódot futtat, amely a következő folyamat futásához szükséges értékeket tölti be a regiszterekbe. Ha a megszakítás kiszolgálása befejeződött, akkor vagy a megszakított folyamat futása folytatódik, vagy az ütemező indul el, és megállapítja a következő végrehajtandó folyamatot.

Az ütemezési algoritmusokat csoportosíthatjuk felépítésük és működésük alapján. A különböző operációs rendszerek használhatóságát nagyban befolyásolja az ütemező algoritmus működése. A klasszikus ütemezési algoritmusok közül a következőket tárgyaljuk:

  • Egyszerű algoritmusok

    • Legrégebben várakozó (First Come First Served, FCFS):

    • Körforgó (Round-Robin, RR)

  • Prioritásos algoritmusok

    • Statikus prioritás

    • Legrövidebb (löket)idejű (Shortest Job First, SJF)

    • Legrövidebb hátralévő idejű (Shortest Remaining Time First, SRTF)

    • Legjobb válaszarányú

  • Többszintű algoritmusok

    • Statikus többszintű sorok (Static Multilevel Queue, SMQ)

    • Visszacsatolt többszintű sorok (Multilevel Feedback Queues, MFQ)

  • Többprocesszoros ütemezés

6.3.2.1. Egyszerű ütemezők

Az egyszerű ütemezési algoritmusok az ütemezésre kerülő folyamatokat minden esetben egyenlőnek, azonos prioritásúnak tekintik.

Egyszerű ütemezők típusai
6.9. ábra - Egyszerű ütemezők típusai


6.3.2.1.1. Legrégebben várakozó (First Come First Served)

A legegyszerűbb algoritmus, a feladat leíróra mutató referenciákat tároló FIFO (First Input First Output) sor az implementáció. Definíció szerint nem preemptív (nemmegszakításos), de I/O-ra várhat. Az átlagos várakozási idő nagy lehet, és erősen függ a feladatok hosszától, és a CPU és I/O löket (burst) nagyságoktól. Ez egyben átlagosan nagy válaszidőt is jelent, on-line felhasználókat is kiszolgáló rendszerek számára nem alkalmas. De kis adminisztrációs overhead jellemzi, a minimális számú kontextusváltás miatt. Az új folyamatok a várakozási sor végére kerülnek, mindig a sor elején álló folyamat kezd futni, a folyamatok nem szakíthatóak meg. (Nem preemptív az ütemező, így valós idejű rendszerhez nem használható.) Az algoritmus előnye az, hogy egyszerűen megvalósítható. Az algoritmus hátránya, hogy egy hosszú ideig futó folyamat feltartja az egész rendszert (Konvojhatás)

6.3.2.1.2. Körforgó (Round-Robin – RR)

Időosztásos rendszerek számára találták ki az egyszerű FCFS ütemezés problémáinak kijavítására. Kedvezőbb az on-line felhasználók számára, mivel jobb az átlagos válaszideje a FCFS-nél. (Adott időnként garantáltan vált, függetlenül a feladattól.) Az algoritmus tehát az időosztásos operációs rendszerek algoritmusainak alapja. Csak időszeleteket kapnak a folyamatok (time slice), amelyek után az ütemező átadja a vezérlést egy másik folyamatnak, így az algoritmus preemptív módon üzemel. Abban az esetben, ha a CPU löket kisebb, mint az időszelet, akkor a folyamat lefut és átadja a vezérlést a soron következő folyamatnak. Ha a CPU löket nagyobb, mint az időszelet, akkor az időszelet lejárta után felfüggesztésre kerül a futó folyamat, és az ütemező átadja a vezérlést a soron következő folyamatnak.

Túl hosszú időszelet esetén az algoritmus ugyanúgy viselkedik, mint az FCFS algoritmus, míg túl kicsire választás esetén megnő a környezetváltások száma, ami a rendszer hasznos teljesítményét jelentősen lerontja. A statisztikai vizsgálatok alapján az időszelet hosszát úgy kell megválasztani, hogy a CPU-löketek kb. 80%-a legyen rövidebb az időszeletnél.

6.3.2.2. Prioritásos ütemezők

A folyamatok futási sorrendjét a prioritásuk határozza meg. A folyamatokhoz prioritást rendelünk, a prioritását különböző attribútumok alapján határozzák meg. Az ütemező a legnagyobb prioritású folyamatnak osztja ki a CPU-t. Ha egyenlő a folyamatok prioritása, akkor az egyenlő prioritású folyamatok között valamelyik egyszerű ütemezési stratégiát használjuk a sorrend eldöntésére. A prioritás meghatározása szempontjából lehet:

  • statikus prioritású rendszer (előre meghatározott prioritás)

    • Tervezési időben teljesen meghatározott, hogy milyen feladatok és mikor futnak.

    • Legrosszabb esetre tervezés.

    • Speciális, többnyire biztonságkritikus beágyazott rendszerekben alkalmazzák.

  • dinamikus prioritású rendszer (futási időben meghatározott prioritás)

    • A gyakorlatban használt algoritmusok ilyenek.

    • Dinamikus erőforrás kihasználás.

    • Tervezési időben nehezen vizsgálhatók.

Prioritásos ütemezők típusai
6.10. ábra - Prioritásos ütemezők típusai


A statikus ütemező az ütemezési döntéseket fordítási időben hozza meg. Egy diszpécser táblázatot generál, amely alapján a program végrehajtásra kerül. A dinamikus (vagy on-line) ütemező az ütemezésre vonatkozó döntéseket futás közben hozza meg. Ezeken belül megkülönböztetünk még preemptív, és nem-preemptív eseteket, azaz amikor az ütemezett folyamat megszakítható, ill. amikor nem szakítható meg. Nem preemptív algoritmus, amely a legrégebben várakozó folyamatot választja ki futásra. Megvalósítása igen egyszerű, a futásra kész folyamatok egy várakozási sor végére fűződnek fel, az ütemező pedig mindig a sor legelején álló folyamatot kezdi futtatni. Ennél az algoritmusnál igen nagy lehet az átlagos várakozási idő, mivel egy-egy hosszú CPU-löketű folyamat feltartja a mögötte várakozókat (ezt hívjuk konvoj hatásnak).

Először a kooperatív multitask-ot valósították meg nagy gépes környezetben. A működési elve és alapötlete a kooperatív algoritmusoknak az, hogy egy adott program vagy folyamat lemond a processzorról, ha már befejezte a futását vagy valamilyen I/O műveletre vár. Ez az algoritmus addig működik hatékonyan, amíg a szoftverek megfelelően működnek (nem kerülnek végtelen ciklusba), és lemondanak a CPU-ról. Ellenkező esetben az egész rendszer stabilitását képes lecsökkenteni vagy akár képes az egész rendszert lebénítani. A kooperatív algoritmus ezért soha nem fordul elő valós idejű operációs rendszerek esetében.

A preemptív algoritmusok esetében az operációs rendszer részét képező ütemező algoritmus vezérli a programok/folyamatok futását. A preemptív multitask esetén az operációs rendszer elveheti a folyamatoktól a futás jogát és átadhatja más folyamatoknak. A valós idejű operációs rendszerek ütemezői minden esetben preemptív algoritmusok, így bármely program vagy folyamat leállása nem befolyásolja számottevően a rendszer stabilitását. Az ütemező algoritmusok az operációs rendszerek rendeltetése alapján más-más rendszerjellemzőkre vannak optimalizálva. Az ütemezési algoritmusok teljesítményét a következő szempontok alapján tudjuk osztályozni:

  • CPU kihasználtság (CPU utilization): Azt mondja meg, hogy a CPU az idejének hány százalékát használja a folyamatok utasításainak végrehajtására.

  • CPU üres járása (Idle): A CPU idejének hány százalékában nem hajt végre folyamatot. (Ilyenkor indíthatóak hosszú távú (long term) ütemezésben szereplő folyamatok.)

  • Átbocsátó képesség (Throughput): Az operációs rendszer időegységenként hány folyamatot futtat le.

  • Körülfordulási idő (Turnaround time): A rendszerbe helyezéstől számítva mennyi idő alatt fejeződik be egy process

  • Várakozási idő (Waiting time): Egy munka (vagy folyamat) mennyi időt tölt várakozással

  • Válaszidő (Response time): Időosztásos (interaktív) rendszereknél fontos, azt mondja meg, hogy mennyi a kezelői parancs/beavatkozás után a rendszer első válaszáig eltelt idő.

Az ütemezési algoritmusokkal szembeni követelményeket különbözőképpen tudjuk csoportosítani. Rendszerenként változhat az, hogy a megvalósításkor melyik követelményt választják fontosnak és melyiket kevésbé. Az algoritmusokkal szemben támasztott fontosabb követelmények a következők:

  • Optimális: Legyen optimális a rendszer viselkedése, azaz valamilyen előre meghatározott szempontok figyelembe vételével működjön a rendszer.

  • „Igazságos”: Ne részesítse előnyben azonos paraméterekkel rendelkező process-ek közül semelyiket sem.

  • Prioritások kezelése: Legyen képes az algoritmus arra, hogy a process-eket, folyamatokat a prioritásuk alapján egymástól megkülönböztessen.

  • Ne „éheztesse ki” a folyamatokat: Minden process kapjon valamennyi processzoridőt, ezáltal biztosítva azt, hogy folyamatos legyen a futás

  • Viselkedése legyen megjósolható: Minden esetben legyen a rendszer viselkedése előre kiszámítható, hogy a mérnökök előre modellezni tudják a rendszer viselkedését.

  • Minimális rendszeradminisztrációs idő.

  • Graceful degradation: Ez a rendszer túlterhelése esetén fontos szempont, mert a rendszer viselkedésének szempontjából az a fontos, hogy „fokozatosan romoljon le” a rendszer teljesítménye. A valós idejű operációs rendszerek esetében kritikus milyen csökkenés engedhető meg, mert a rendszernek tartani kell a valós idejű rendszer specifikációjában meghatározott időket. Ha a rendszer terhelése eléri az könyökkapacitást, akkor utána viselkedése megváltozik, a tovább növekvő terhelésre már egyre rosszabb működéssel reagál (overhead).

Prioritásos ütemező algoritmusoknál a folyamatokhoz az ütemező hozzárendel egy prioritásértéket, és a legnagyobb prioritású folyamat kapja meg a futás jogát. Ezeknél az algoritmusoknál megkülönböztethetünk statikus, és dinamikus prioritásos algoritmusokat. A statikus prioritásos algoritmusoknál a folyamatok kiéheztetése léphet fel, ezért a folyamatokat öregíteni (aging) kell.

  • Legrövidebb (löket)idejű (Shortest Job First – SJF): Az algoritmus a dinamikus prioritásos algoritmusok közé tartozik, a várakozó folyamatok közül a legrövidebb löketidejűt indítja el.

  • Legrövidebb hátralévő idejű (Shortest Remaining Time First – SRTF): Az algoritmus szintén dinamikus prioritásos algoritmus. Ha egy új folyamat érkezik, akkor az ütemező megvizsgálja a futásra kész folyamatok hátralévő löketidejét, és a legrövidebb hátralévő idejű folyamatot indítja el.

  • A legjobb válaszarányú algoritmus (Highest Response Ratio - HRR): Dinamikus prioritásos algoritmus. A prioritásos algoritmusok nagy hátránya a kiéheztetés veszélye. (Vagyis, hogy a kis prioritású folyamatok elől a nagyobb prioritásúak „ellopják” a CPU-t.) Ennek kivédése az öregítés (aging) segítségével történhet, ezáltal a rendszer a régóta várakozó folyamatok prioritását fokozatosan növeli. Ezt az elvet alkalmazza az SJF-ből kiindulva a HRR-algoritmus. A folyamatok kiválasztásánál a löketidő mellett a várakozási időt is figyelembe veszi. A prioritás alapjául a (Löketidő + k*Várakozási idő)/Löketidő összefüggés szolgál (k egy alkalmasan megválasztott konstans).

6.3.2.3. Többszintű algoritmusok

A többszintű algoritmusok esetében a folyamatok több sorban várakoznak (például: rendszer, megjelenítés, batch folyamatok, stb.). Minden sorhoz prioritást rendel az ütemező algoritmus. A sorokon belül különböző kiválasztási algoritmusok is használhatóak. A többszintű algoritmusoknak kettő fő típusa van: statikus többszintű sorok (folyamat nem kerülhet át másik ütemezési sorba) és a visszacsatolt többszintű sorok (folyamat átkerülhet másik ütemezési sorba). A hatékony többprocesszoros ütemezés a mai processzorok esetében elengedhetetlen, mivel a jelenleg piacon kapható számítógépek már több maggal rendelkeznek. A beágyazott alkalmazásokhoz fejlesztett számítógépek is több processzormagot alkalmaznak. A többprocesszoros ütemezést több CPU-val rendelkező rendszerekben vagy több magos/szálas CPU-k esetében lehet használni. Az ütemezési algoritmusokat heterogén és homogén rendszerek csoportjára bonthatjuk. Heterogén rendszer esetében egy folyamat csak 1 CPU-n futhat. Homogén rendszer esetében az induló folyamat a rendszer közös sorába kerül. Homogén ütemezés esetében beszélhetünk aszimmetrikus és szimmetrikus rendszerről. Aszimmetrikus rendszer esetén egy közös (meghatározott CPU-n futó) ütemező van, a szimmetrikus esetében viszont minden CPU saját ütemezőt futtat.

6.4. Task-ok közötti kommunikáció

Mivel a rendszer működése közben a task-ok egymással párhuzamosan futnak, gondoskodni kell arról, hogy egyazon I/O-t, perifériát vagy memória területet két vagy több folyamat ne használjon egyszerre, mert abból hibás rendszerműködés alakulna ki. A taszkok közötti kommunikációra a következő módszerek állnak rendelkezésre:

  • Szemafor (semaphore), mely 1 bit információ átadására alkalmas.

  • Események (event flags), melyek több bit információ kicserélésére is alkalmasak.

  • Postaláda (mailbox), amely komplexebb struktúra átadására szolgál.

  • Sor (queue), amely több mailbox tömbjében tartalom átadására szolgál.

  • Cső (pipe), amely direkt kommunikációt tesz lehetővé két taszk között.

A szemafor egy absztrakt adattípus, amelyet leginkább közös erőforrásokhoz való hozzáférés kontrollálására (kölcsönös kizárás) használnak. Ezen kívül alkalmas még egy esemény bekövetkeztének jelzésére, két folyamat tevékenységének összehangolására, és folyamatok szinkronizálására is. Szemafor típusai a következők lehetnek:

  • Bináris szemafor (binary semaphore), amely egyszerű igaz-hamis jelzésre szolgál. Csak egyetlen erőforrás vezérlésére használható.

  • Számláló szemafor (counting semaphore): A szemaforhoz egy számot rendelünk, működés közben a szemafor wait() művelete blokkol, ha a számláló 0 érékűre változik. Ellenkező esetben eggyel csökkenti a számláló értékét. A szemafor signal() művelete eggyel növeli a számlálót.

  • Erőforrás szemafor (resource semaphore): Csak az a taszk engedhető el, amelyik lefoglalta az adott perifériát. Közös erőforrás védelmére jó, de taszkok közötti szinkronizációra nem alkalmas.

  • Mutex: Egy bináris szemafor, mely kibővített tulajdonságokkal rendelkezik.