400 likes | 495 Views
Operációs Rendszerek II. 5. előadás 2007. március 05. Múlt óra…. A folyamat: Program végrehajtás alatt álló példánya Erőforrás hozzárendelés alapja Folyamat környezete Terület a központi memóriában (kód, adat, stack) Adatok és státuszinformációk a processzor regisztereiben
E N D
Operációs Rendszerek II. 5. előadás 2007. március 05.
Múlt óra… • A folyamat: • Program végrehajtás alatt álló példánya • Erőforrás hozzárendelés alapja • Folyamat környezete • Terület a központi memóriában (kód, adat, stack) • Adatok és státuszinformációk a processzor regisztereiben • Egyéb státuszinformációk (pl. erőforrásokkal kapcsolatos) • A folyamat állapot-információk leírására az ún. PCB szolgál • Egy végrehajtási szál (most éppen melyik utasítást kell végrehajtani) • Ütemezés: folyamatok közötti váltás • Folyamat váltáskor a teljes folyamat környezetet meg kell őrizni – ez biztosítja a folytathatóságot!
Folyamatok létrehozása (Unix) • Teljesen eltérő megoldás (eléggé fura) • A program indítása két részből áll • Aktuális folyamat duplikálása (szülő-gyerek) • Az indítandó program betöltése a gyerek folyamat helyére • Sokat kritizált, de a mai napig élő megoldás
Folyamat duplikálás – fork() … … mypid = fork() if(mypid == 0){ // child … } else { // parent … } … … mypid = fork() if(mypid == 0){ // child … } else { // parent … } mypid = fork() If(mypid== 0) { // Child printf(“%ld – I’m the parent\n”, getpid()) } else { // parent printf(“%ld – I’m the parent\n”, getpid()) }
fork() tovább int a = 1; int b = 2; If(fork() == 0) { printf(“Gy:\t%d, %d\n”,a,b); a += 2; printf(“Gy:\t%d, %d\n”,a,b); } else { printf(“Sz:\t%d, %d\n”,a,b); sleep(1); printf(“Sz:\t%d, %d\n”,a,b); } Gy: 1,2 Sz: 1,2 Gy: 3,2 Sz: 1,2
fork() • A fork() hatására a teljes folyamat címterét és az erőforrás adatokat is duplikáljuk • A duplikálás után a címterek függetlenek, a változók külön élnek (a kezdőérték ua.) • A fájlokat mindkét folyamatból el lehet érni (ha mindkettőből írunk, akkor a kimenet összekeveredve jelenik meg)
exec() • A fork() érdekes, de hogyan indítunk új programot? • Az exec() hívás az éppen futó folyamat „helyére” tölt be (és indít el) egy programot • A pid nem változik és az erőforrás leírók is öröklődnek (pl. így működik a pipe a shell-ben)
Folyamat-leírók • Erőforrás menedzsment megvalósításához az operációs rendszernek elegendő információval kell rendelkeznie a folyamatok és az erőforrások mindenkori állapotáról • Ezt OS különböző táblázatok fenntartásával valósítja meg. Tipikus táblázatok: • Memória tábla (fizikai és VM is) • I/O tábla • Fájl tábla • Folyamat tábla
Folyamat-leírók • Memória tábla (fizikai és VM is) • memória – folyamat összerendelés, • védelmi információk, • VM információk • I/O tábla • Processz információ • Státusz • Memória info (pl. puffer terület) • Fájl tábla • Adattartalma attól függ, hogy a fájlkezelés feladatai milyen módon oszlanak meg az OS és az alkalmazás között • Folyamat tábla
Folyamat-leírók • A táblázatok függenek egymástól, hivatkoznak egymásra (pl. fájl és I/O, folyamat és mindegyik). • A táblázatokat inicializálni kell, meg kell határozni határértékeket. Ez történhet: • konfiguráció alapján (statikus) • dinamikusan
Operációs rendszer végrehajtása • Az operációs rendszer is egy program, amelyet a CPU hajt végre • A teljes rendszer működtetéséért az OS felel, önmagát teljesen nem menedzselheti (tyúk vagy tojás) • Operációs rendszer végrehajtási modellek • Nonprocess kernel • Folyamat címterében futó kód • Folyamat alapú kernel
Modellek • Nonprocess kernel • Folyamatok fogalma kernel szinten nincs • Kernel teljesen szeparált, saját törvényei szerint fut • Folyamat címterében végrehajtott kernel kód • Mernel nem folyamat alapú, (user) folyamatok címterében fut • Minden folyamat címterében elérhető (folyamatok nem látják) • Folyamat alapú kernel • Kernelt is folyamatokként valósítjuk meg • Kliens-szerver modell • többprocesszoros rendszeren is hatékony • Kell egy folyamat váltási funkció, ami a folyamatok „alatt” fut
Mikrokernelek – miért? • Operációs rendszerek fejlődése • Teljesen monolitikus kód (több millió sor) • Struktúrált felépítésű, rétegelt kód • Mikrokernelek • Miért nem eléggé jó a struktúrált kód? • Kernel módban a súlyos hibák végzetesek • Kernel kódot nehéz írni • A növekvő funkcionalitás miatt egyre több és több kód kell(ene)!
Hogyan is működnek az OS funkciók? • Különféle kernel funkciók (pl. lapcsere memóriakezelés esetén) • Döntés (politika): lap helyének kiválasztása • Végrehajtás: a tényleges lapbetöltés • A végrehajtás tipikusan hardver közeli, de a döntés nem igazán ha megfelelő adatok rendelkezésre állnak, a döntési rész akár kernelen kívül is futhat(na)
Mikrokernel: A kernel csak az alapfunkciókat tartalmazza, a kód többi részét felhasználói módban futó szolgáltatások valósítják meg. Erősségei: • Egységes interfész • Bővíthető • Flexibilis • Hordozható • Megbízható • Elosztott rendszerek támogatása • OO támogatása
Mikrokernel: A kernel csak az alapfunkciókat tartalmazza, a kód többi részét felhasználói módban futó szolgáltatások valósítják meg. Gyenge pontok: • Kernel és felhasználói mód közötti váltás erőforrásigényes (lassúság) kernelbe épített funkciók aránya • Teljesen új koncepció, gyakorlatilag nulláról újra kell írni a rendszereket Az igazán elterjedt rendszerekben tisztán nem igazán lehet találkozni vele (talán: Mach OpenStep Mac OS X)
Tipikus mikrokernel (alap)funkciók • Alacsonyszintű memória menedzsment • IPC • IRQ kiszolgálás • I/O kezelés (alacsony szinten)
Szálak – miért? • Programok egyre több párhuzamosan is végrehajtható részfeladattal bírnak • Szerver megoldások (web, file) • Kliensek esetén háttérfunkciók (backup, stb.) • Előtér párhuzamosítás (pl. web böngésző) • A több (sok) processzor kihasználásához párhuzamosan végrehajtható kód! • Ezek a kódok nem függetlenek – közös adatok, együttműködés (szinkronizáció)!
Problémák • Természetes megoldás: párhuzamos kód több folyamat (hiszen erre való) • Ez így jó (is volt sokáig), de: • Létrehozásuk, megszűntetésük drága • Kommunikáció, együttműködés (drága) kernel műveletekkel lehetséges • Folyamatok közötti váltás költséges • Általában: kernel funkciók futtatása drága! Szálak
Szálak • Alapötlet: válasszuk külön az erőforrások birtoklását a program futtatásától! • Folyamat: erőforrás foglalás alapegysége (mint eddig is) • Szál: folyamaton belüli futási végrehajtás egysége • Egy folyamaton belül egyszerre több végrehajtási szál is létezhet
A folyamathoz képest… • Gyorsabb végrehajtás • Gyorsabb terminálás • Egy folyamaton belül • A szálak közötti váltás gyorsabb, mint a folyamatváltás • A szálak közötti adatcsere, kommunikáció kernel funkciók igénybe vétele nélkül zajlik • Nem a folyamatok helyett van!
Megvalósítási lehetőségek • Felhasználói szálak • Kernel szálak • Hibrid megoldások
Felhasználói szálak • Kernel nem tud róla, továbbra is folyamatokat lát • Szálmenedzsment alkalmazás szintű kóddal (lib) • Szálütemezés folyamatonként eltérő lehet • Előnyök • szálváltás gyors (user módban fut) • OS-től független, hordozható megoldás • Korlátok • I/O blokkolhatja az összes folyamat-szálat (aszinkron I/O) • 1 folyamat összes szála 1 CPU! • Signal-ok kezelése nem triviális
Signal-ok kezelése • Aszinkron események (nem szinkron válasz egy hívásra) • Felhasználói szálak esetén a kernel csak folyamat szinten tudja ezeket az eseményeket kezelni • Ez is a thread könyvtár problémája…
Kernel szálak • A teljes szálmenedzsment kernel módban • Felhasználói szinten csak API van • A szálak ütemezést a kernel végzi • Erősségek • egy szál blokkolódása nem blokkolja a teljes folyamatot • folyamat szálai több CPU-n is futhatnak • Signal kezelés megoldott • Korlátok • drága
Mennyire „olcsó”? • Gyorsabb a létrehozás (kb. 20x) • Gyorsabb a terminálása • Egyazon folyamat szálai között • Gyorsabb váltás • Szálak közötti kommunikáció user címtérben zajlik, a kernel nélkül! • 1992, VAX-on végzett mérések (UNIX-szerű környezet)
Hibrid szálak • A felhasználói szálak alkalmazás szinten értelmezettek, de vannak szálak kernel szinten is. • A kernel LWP-k (LightWeight Process) szintjén látja a folyamatokat (ezek 1:1-ben kapcsolódnak kernel szálakhoz) • Az LWP-k és a felhasználói szálak közötti kapcsolatot felhasználói szintű kód menedzseli • A felhasználói szálak és LWP-k aránya dinamikus, de kódból is módosítható • A Solaris 10-ben már nincs meg ez a megoldás!
Adatok, struktúrák • kell privát stack (user mindig, kernel szálak esetén kernel stack is) • szálaknak is van állapota /ready, run, blocked/ és prioritása, a CPU regisztereket menteni kell: TCB (a PCB-vel analóg módon)
Szálműveletek • POSIX threads (felhasználói szintű szál-könyvtár) szolgáltatások • Szálak létrehozása és megszűntetése • Üzenetek és adatok átadása szálak között • Szálak végrehajtásának ütemezése • Szál környezet mentése és visszaállítása
Jön, jön, jön… • Folyamatok és szálak megvalósítása különféle operációs rendszerekben (adattáblák, leírók) • Folyamatok ütemezése • Folyamatok közötti szinkronizáció és kommunikáció