Betriebssysteme Tutorial - Holger Kreissl -
www.kreissl.info |
Kapitel 1 - Einleitung Betriebsysteme
- Hauptaufgaben einen Betriebssystems
- Unterschiede zwischen Betriebssystemen
- Bestandteile von Betriebssystemen
|
Einleitung - BS Definition Ein Betriebsystem
stellt Dienste und
Infrastrukturen (Metasteuerungen)
bereit. Daten oder Virtuelle Maschinen sind kein Teil
des Betriebssystems sondern des Dienstleistungssystems.
Die Metasteuerungen sind entscheidend beim Entwurf.
(z.B. in Bezug auf Uni- oder
Mehrbenutzersystem)
Grob gesagt ist ein
Betriebssystem eine erweiterte Maschine
(Top-Down-Sicht), um durch Abstraktionen eine für den
Menschen (Programmierer) überschaubare Form als
Programmiergrundlage zu bieten.
Definieren Sie den Begriff Betriebsystem! Das
Betriebssystem ist die Gesamtheit der
Programme eines Rechensystems, welche die
Betriebssteuerung erledigen und die Benutzeraufträgen
eine zugängliche Umgebung bereitstellen. Betriebsmittel
sind Komponenten sowohl der Hardware als auch der
Software (System und Anwendersoftware), wie z.B.
Prozessor, Speicher, Ein-Ausgabe-Geräte, Dateien,
Programme etc.
Das Betriebssystem ermöglicht es
z.B. dem Anwender, Programme auf unterschiedlicher
Hardware laufen zu lassen. D.h. das Betriebssystem
bietet dem Anwender eine virtuelle
Maschine, welche die reale Hardware
"unsichtbar" für den Programmierer macht.
- abstrahiert den Rechner auf eine für Menschen
leichter durchschaubare virtuelle Maschine
- Steuert und koordiniert Prozessabläufe und
verwaltet die Ressourcen
Merktabelle: Definition
Betriebssysteme
Wie sieht das Ebenen- oder Schichtenmodell eines
Rechners aus?
- Gatter Ebene
- Mikroprogrammebene
- konventionelle Maschinenebene
- Betriebssystemebene API
- Assemblerebene
- Anwendungsebene
Worin Unterscheiden sich Betriebssysteme?
- universal oder dezidiert (Multi-Task /
Single-Task)
- eine oder mehrere Sitzungen (Windows < XP,
Linux)
- Kommunikation mit der Umwelt (Batch, interaktiv
oder in Echtzeit)
Was sind die drei Welten des Betriebsystems?
- Betriebssystem selbst
- Komplexe Werkzeuge, wie aufgesetzte Dienste oder
Virtuelle Maschinen
- Programmiersysteme zur Entwicklung von
Erweiterungen
Welche Aufgaben hat ein Betriebsystem?
- Abstraktion der Hardware, d.h. Schließen der so
genannten 'Semantischen Lücke' zwischen
Mikroprogrammebene und der Anwendungsebene
- Betriebsmittelverwaltung
- Steuerung von Peripheriegeräten (I/O,
Festplatten...)
- Steuerung des Betriebsablaufs durch
Prozessverwaltung und -Kommunikation und Organisation
des Mehrprogrammbetriebes
- Protokollierung, Schutz und Sicherheit
- Behandlung von Ausnahmesituationen, wie Page
Faults, Division by Zero u.s.w.
- Bereitstellung einer Kommandosprache
- Unterstützung von Administrationsaufgaben
(Datensicherung, Systemkonfigurierung, Benutzerrechte)
Was ist ein Modell? Ein Modell eines
Rechnersystems ist eine Abbildung eines realen
Systems unter Abstrahierung bestimmter
Kriterien, in dem eine formale Beschreibung durch eine
Theorie in Gesetzen formuliert werden kann.
Welche drei Punkte sind bei der Realisierung eines
BS grundlegend? Prozessor-Modes
(Betriebszustände)
Supervisor Mode (Kernel Mode)
|
Ist ein privilegierter Modus für
Betriebssystemfunktionen im Kern des Systems,
welches Sicherheit des Systems erhöht, da diese
geschützt von Andwenderprogrammen laufen. |
User Mode (Anwendungsmodus) |
Die Betriebsart wird über ein
"Mode"-Bit angezeigt. Privilegierte Funktionen
(wie I/O Funktionen) sind aber nur im Kernelmode
ausführbar. Diese können über bestimmte Methoden
gerufen werden.
| Kernel
Im
Kern laufen die Systemkritischen Funktionen, wie z.B.
I/O-Aktionen ab. Der Kern muss korrekt, sicher und
geschützt vor Anwendungen sein.
Methoden des
Aufrufs von Betriebssystemsdiensten
System Calls |
Durch System Calls
können BS-Funktionen gerufen werden. Die
Schnittstelle zwischen Usermode und Kernel sind
sogenannte Traps (Einstiegspunkte). Geräte können
Traps nicht nutzen, sondern können die BS-Dienste
durch spezielle Interruptsmechanismen erreichen.
|
Nachrichtenversand |
Über eine
Send/Receive-Schnittstelle können
sich User-Mode und Kernel-Mode Nachrichten
zuschicken. | Sinn und zweck
ist eine Entkopplung von System und Anwendung! Windows
NT bietet eine API mit mehr als 10.000 Systemaufrufen,
Unix dagegen ca. 300.

|
| |
|
Kapitel 2 - Modelle
- Modelle für Betriebssysteme
- Hierarchiche Schichtenmodell
- Betriebsmittel und Instanzen
- Schalenmodell
- Modulmodell (Monolithisches Modell)
- Hierarchisches Schichtenmodell
- Client Server Modelle
|
Vor- und Nachteile von Schalen- und Modulmodellen
Schalenmodell:
- Relationen der einzelnen Schalen sind zur Umwelt
nicht sichtbar
- System ist aber gut strukturiert
- Innere Schalen sind sehr gut abgeschirmt von den
Äußeren
Modulmodell:
- Das Modell wird in Modulen durch Programmcode
beschrieben
- die Relationen werden daher extrem komplex
(quatradisch)
- Daher ist es nur bei kleinen Modellen umsetzbar
Wie ist das hierarchische Schichtenmodell aufgebaut?
Jede Schicht stellt Betriebsmittel und Dienste für
den Zugriff auf die jeweilige übergeordnete Schicht
bereit. Somit kann jede Schicht auch die Betriebsmittel
und Dienste darunterliegender Schichten nutzen. Eine
Schicht steuert die unmittelbare Schicht über ihr.
(Steuerungshierarchie)
Bestandteile:
- Schichten
- Iterative Ordnungsrelation der Schichten (Dienste,
Steuerungen bzw. Instanzen)
- Betriebsmittel
- Funktionen zum Erzeugen von Betriebsmitteln und
Steuerungen
Welche Vorteile hat das hierarchisch
Schichtenmodell?
- obwohl modularisiert, ist die Zahl der Relationen
gering
- Kommunikation mit der Umwelt ist möglich
- Es bietet eine Infrastruktur für Instanzen
(Steuerung, BM-Transformationen)
Was ist ein Betriebsmittel? Ein Betriebsmittel
ist eine abstrakte Ressource, welche über eine Adresse
und einen Wert verfügt. Sie wird definiert über
- ID (eindeutiger Identifikator)
- Adressbereich (für alle möglichen Adressen des
Betriebsmittels)
- Wertebereicht (aller möglichen Werte für einen
Wert des BM)
- Funktion (verknüpft die abstrakten Elemente
miteinander)
Der Zustand eines
Betriebsmittels ergibt sich aus Wert x Adresse.
Welche Klassen von Betriebsmitteln gibt es?
- Entziehbarkeit (entziehbar wie Prozessor oder
nicht wie Dateideskriptor)
- Zuteilbarkeit (gleichzeitig wie Speicher oder
exklusiv wie Prozessor oder Drucker)
- Wiederverwendbarkeit (einmalig Nutzbar wie
Interrupt oder mehrfach wie Prozessor oder Speicher)
- Hardware / Software (logisches oder physikalisches
Betriebsmittel)
Vorgehensweise beim Erstellen eines Betriebsmittels
- ID bestimmen
- abstrakte Elemente bestimmen, welche einen Wert
und eine Adresse besitzen
- Wert und Adresse festlegen
- Funktionen definieren, welche Zugriff auf alle
Elemente ermöglichen
Erläutern sie die Betriebsmittelerstellung am Bsp.
Hauptspeicher!
- Eine ID ist hier nicht sinnvoll, da ein
von-Neumann Rechner nur einen Hauptspeicher hat.
- die abstrakten Elemente sind die ansprechbaren
Speicherzellen mit Adresse und Wert.
- Der Wertebereich beträgt 0 bist 255 bei einem
Byte-Orientierten Speicher
- Funktionen sind Read und Write eines Elementes zum
Speicher
Was ist eine Instanz? Eine Instanz ist ein
Tupel aus id (Betriebsmittel) und einem Aktivitätstoken,
welches die einzelnen Dienste ruft. Zwischen
Betriebsmitteln untereinander und zwischen Instanzen
untereinander bestehen Relationen.
Wechle Klassen von Instanzen kennen Sie?
- Applikationen
- Betriebsmittel-Transformatoren
- Metasteuerungen wie PUM
Wie können Relationen zwischen Instanzen technisch
hergestellt werden? Protokolle und Schnittstellen
verbinden sich Instanzen. Dabei treten beide immer
zusammen auf. Eine Schnittstelle kennzeichnet das
statische Verhalten einer Relation und ein Protokoll das
dynamische, d.h. die Semantik der Relation.
Als
Beispiel nehmen wir einen Spooler. Hier ist die
Schnittstelle ein Betriebsmittel (Speicherbuffer) und
das Protokoll (Verhalten) ist als Dienst
implementiert.
Spool = Simultanously Periphal
Output On Line
Es gibt datenorientierte und
steuerungsorientierte Schnittstellen. Datenorientierte
Schnittstellen arbeiten ohne Synchronisation und
verbrauchen viel Ressourcen (Busy Waiting).
Steurerungsorientierte Schnittstellen sind z.B.
Systemcalls und Interrupts. |
| |
|
Kapitel 3 - Aktivitäten
- Was sind Aktivitätstoken?
- Welche Arten von Token gibt es?
- Was sind Prozesse?
- Unix Prozesserzeugung
- Zustände von Prozessen
|
Was ist ein Aktivitätstoken?
- Ist sehr abstrakt zu sehen
- Ein Aktivitätstoken haucht dem Programm erst
"Leben" ein
- Beschreibt ein aktiven oder wartenden Prozess
- Es muss eine Art virtuellen Programmcounter im
eigenen virtuellen Steuerwerk des Prozesses geben
Was ist Multitasking? Ist die Fähigkeit
Prozesse parallel laufen zu lassen. Bei
Einprozessormaschinen (kooperativ oder preemtiv) wird
die Leistungsfähigkeit damit optimal ausgenutzt. Die
verschiedenen Betriebsmittel können von mehreren
Prozessen mehrfach bzw. parallel genutzt werden.
Welche Aktivitäten gibt es und worin unterscheiden
sie sich?
|
Token |
Verteilung |
Protokoll |
BM-Zuteilung |
Prozedur |
Eins für alle |
- |
Call Return |
Exclusiv |
Coroutine |
Eins für alle |
- |
Resume, aber dynamischer
Eintrittspunkt (kooperatives Multitasking) |
Exclusiv |
Prozess |
Pro Prozess |
Pro Prozess |
Keine Übergabe, da Prozess Token
behält |
Exclusiv |
Thread |
Pro Prozess |
Pro Thread Eins |
Keine Übergabe, da Prozess Token
behält |
Threads sind in Prozessen
gruppiert und teilen sich dort die Betriebsmittel
|
Welche Betriebsmittel benötigt eine Aktivität
mindestens?
- Programmcode
- Hauptspeicher
- Steuerwerk
Wodurch wird ein Prozess beschrieben?
- ein im System eindeutiger Identifikator (PID)
- Liste mit Betriebsmittel-Forderungen
- Liste mit zugeteilten Betriebsmitteln
- Ein Folge der bisherigen Anweisungen
- Die Anfangswertbelegungen der zugeteilten
Betriebsmittel
Welche Probleme treten mit Prozessen auf?
- Determiniertheit (Durch Mehrfachverwendung von
Betriebsmitteln ist diese so nicht mehr gegeben und
Synchronisation wird notwendig)
- Mutual Exclusion
- Synchronisation (Abstimmung zwischen Threads)
- Kommunikation (Synchronisation und Austausch von
Daten zwischen Prozessen)
- Lebendigkeit
Welche Zustände kann ein Prozess einnehmen?
- nicht existent (Prozess noch nicht definiert)
- bereit (besitzt alle angeforderten Betriebsmittel
außer den Prozessor)
- aktiv (besitzt mindestens die angeforderten
Betriebsmittel)
- wartend (wartet noch auf noch nicht zugeteilte
Betriebsmittel)

Wie wird ein Prozess im Unix erstellt?
- mit Systemaufruf fork() wird ein komplettes
Speicherabbild eines schon bestehenden Prozesses
erzeugt (bei NT wird Prozess mit einem Initialzustand
erstellt)
- Deshalb erben neue Prozesse eventuelle Variablen
des Vaterprozesses
Deshalb terminiert folgende
Schleife nicht unter NT aber unter Unix:
For ( i=1; i<3; i++) fork();
Einige Unix-Systembefehle zur Prozesserzeugung:
- fork(), vfork() zum Prozesserstellen mit
Speicherabbild des Vaters
- clone() erstellt einen Prozess der der den
Speicher und Deskriptoren mit Vater teilt
- execl(), execv(), execle(), execlp(), execvp() zum
Kopieren eines Programms in den Speicher
- wait(), waitpid() zum Warten auf Ende des
Sohnprozesses
- exit() zum Beenden eines Prozesses
http://unixhelp.ed.ac.uk/CGI/man-cgi
Ein Beispielcode für eine Einfache Unix-Shell #include sys/types.h
#include sys/wait.h
#include unistd.h
#include stdlib.h
#include stdio.h
#include string.h
using namespace std;
int main(void){
pid_t pid; //für PID des Sohnes
char str1[1000]; //Befehlsbuffer
while(1){
printf("\nDiggs mini bash. (PID=%d)\n\n",getpid());
printf("> ");
scanf("%s",str1); //Befehl lesen
if (strcmp(str1,"exit")==0) break; //exit beendet
if ((pid=fork())<0) //Prozess kopieren
{
printf("EXEC Operation failed!\n\n");
exit(0);
}
if (pid==0) //im Sohnprozess exec
{
char *cmd=strtok(str1," ");
execlp (cmd,cmd,0); //Speicher überschreiben
printf("command not found!\n");
exit(0); //manuell terminieren
} //Vaterprozess muss warten
else waitpid(pid,0,0);
}
return 0;
}
Der Vaterprozess liest einen Befehl (hier nur ohne
Parameter) und startet danach einen Sohnprozess mit
fork() in welchem mit dem Befehl exec das aufzurufende
Programm in den Speicher kopiert wird. Schlägt exec fehl
muss mit exit der Sohnprozess manuell beendet werden, da
dieser sonst nicht terminieren würde.
Am Besten
einfach ausprobieren. Den Quellcode eingeben oder
kopieren und mit dem gcc compilieren:gcc minishell.cc -o minishell
Aufruf: ./minishell
Wie werden Prozesse verwaltet? Das
Betriebssystem verwaltet alle Prozesse. Die Prozesse
besitzen einen PCB (Process Controll
Block, in welchem alle zum Prozess gehörigen
Informationen gespeichert werden. Das Betriebssystem hat
nun die Aufgabe alle n Prozesse auf einen oder mehr
Prozessoren abzubilden.
Was ist Timesharing? Timesharing ist die
gemeinsame Benutzung des Betriebsmittels
Prozessor von mehreren Prozessen. Dabei
ermittelt ein Scheduler den nächst auszuführenden
Prozess. Ein Task-Switch bzw. Context-Switch bezeichnet
eine solche Umschaltung zwischen den Prozessen.
Was sind virtuelle Geräte bzw. Betriebsmittel?
Virtuelle Geräte stellen durch das Betriebssystem
simulierte Geräte mit idealisierten
Eigenschaften dar. Bewerkstelligt wird damit die
Abstraktion von den Eigenschaften realer Geräte mit dem
Ziel der Geräteunabhängigkeit. In der Regel stellen
virtuelle Geräte jedem Prozeß eine synchrone Operation
zur Verfügung. Dabei kann es erheblich mehr virtuelle
als reale Geräte geben. Beispiele für virtuelle
Betriebsmittel sind Druckerspooler oder Dateien. |
| |
|
Kapitel 4 - Kritischer Abschnitt
- Kritischer Abschnitt und Mutual Exclusion
- Dezentrale und Zentrale Steuerungen
- Semaphore und ihre Impementierung
- Verschiedenen Synchronisationsprobleme
|
Was ist ein Kritischer Abschnitt? Ein
Kritischer Abschnitt ist ein zeitlicher Bereich, in
welchem mindestens zwei Prozesse auf das gleiche
Betriebsmittel zugreifen und mindestens eines davon
schreibt. (Zeitkritischer Ablauf)
Erklären sie am Bsp. Druckerspooler den kritischen
Abschnitt!
- in Spooler ist der Platz 4 frei
- Prozess A will drucken und liest die Platznummer
- PUM aktiviert Prozess B, welcher ebenfalls diese
Platznummer liest
- Prozess B schreibt den Auftrag nach Platz 4
- PUM schaltet zu A zurück und A überschreibt nun
den Druckauftrag von B!
Deshalb
notwendig: Wechselseitiger Ausschluss!
Warum werden keine Interrupt Unterbrechungen zur
Synchronisation verwendet? Ein Prozeß der auf
gemeinsame Daten und Ressourcen zugreift, kann nicht
einfach alle Interrupts abschalten. Dies würde zu keinem
optimalen Scheduling führen, weil dann jeder Prozeß
solange die Kontrolle behalten darf wie er will. D.h.
die wartenden Prozesse sind auf die Kooperation des
gerade laufenden Prozesses angewiesen (kooperatives
Multitasking wie Win 3.11)
Was ist wechselseitiger Ausschluss? Es muss
gewährleistet werden, daß niemals sich mehr als ein
Prozess in einem kritischen Abschnitt befinden darf. Die
Anwendung einer einfachen Sperrvariable ist hier nicht
möglich, da der Zugriff und das Setzen dieser, selbst
einen kritischen Abschnitt darstellt. Es müssen
Algorithmen gefunden werden, welche die Funktionalität
gefahrlos implementieren.
Welche Anforderungen muss eine Steuerung für
kritische Abschnitte erfüllen?
- exklusive Nutzung durch verschiedene Teilprozesse
über mutual exclusion
- Ein Prozess darf einen anderen nur behindern, wenn
beide im kritischen Abschnitt
- Der Eintritt in einen kritischen Abschnitt darf
nicht lang dauern
- Alle Prozesse müssen in endlicher Zeit ihre
Betriebsmittel zugewiesen bekommen
- globale Unabhängigkeit von allgemeinen
Fortschreiten der Prozesse
Welche dezentralen Steuerungen kennen Sie? (aktives
Warten)
- Test and Set Lock
- Ping-Pong (Striktes Alternieren)
- Decker Algorithmus
- Peterson Algorithmus
Wie arbeitet Striktes Alternieren? (Ping Pong)
Prozess A |
Prozess B |
While (1)
{
while (turn!=FALSE);
criticalsection();
turn = TRUE;
notcriticalstuff();
}
|
While (1)
{
while (turn!=TRUE);
criticalsection();
turn = FALSE;
notcriticalstuff();
}
|
Hier wird nur mit einer TURN
Variable zwischen den Prozessen hin und her
geschalten. Nachteil ist das die Abläufe nur
abwechselnd in die kritischen Abschnitte eintreten
können und das ein nicht im kritischen Abschnitt
arbeitender Prozess trotzdem warten muss, bis der
andere diesen wieder verlassen hat.
|
Wie schaut Peterson's Algorithmus aus?
CONST N = 2; //konkurrierende Prozesse
INT turn; //Container für aktiven Prozess
INT interested[N];
void P(int process) //Eintreten
{
int other = 1-process; //Gegenteil des Prozesses
interested[process] = TRUE; //Interesse bekunden
turn = process; //Flag setzen
while(( turn==process ) AND (interested[other]==TRUE));
}
void V(int process) //Welcher Prozess verläßt K.A.
{
interested[process]= FALSE; //Kein Interesse mehr
}
Das turn erzwingt ein Warten des interessierten
Prozesses, solange ein andere Prozess im K.A. ist. Der
Hauptnachteil von dezentralen Steuerungen für kritische
Abschnitte ist das Aktive Warten (Spin Locks), was
bedeutet, dass die Blockierzeit anderer Prozesse nicht
genutzt werden kann.
Was sind Semaphore - zentrale Steuerung? Ein
Semaphor ist ein allgemeiner Mechanismus zur
Synchronisation, ohne aktiv warten zu müssen. Das
Verfahren wurde von Dijkstra (1965) entwickelt und hat
sich durchgesetzt. Ein Semaphor arbeitet auf einer
priviligierten Schicht des Betriebssystems und ist somit
nicht Teil der Prozesse. Ein Binärer Semaphor kann
einen Kritischen Abschnitt für zwei Prozesse verwalten.
Falls mehrere Prozesse gleichzeitig auf ein
Betriebsmittel zugreifen dürfen, reicht der binäre
Semaphor nich aus. Der Semaphor wird dann als Zähler
implementiert. Falls er 0 ist, ist das Betriebsmittel
voll ausgelastet. Ist er größer als 0, so sind noch
Ressourcen vorhanden, d.h. andere Prozesse dürfen in den
Kritischen Abschnitt eintreten, solange der Semaphor
nicht Null ist. Dabei dekrementieren sie diesen und
blockieren ihn für andere Prozesse, falls der Semaphor
nun Null ist. Verläßt ein Prozess den Kritischen
Abschnitt, inkrementiert der Prozess den Semaphor wieder
und signalisiert damit, dass er seine Arbeit getan hat
und nun ein anderer eintreten darf. Daher werden die
beiden Operationen vor und nach dem Kritischen Abschnitt
oft als Down(sem) und Up(sem) definiert.
Wie funktioniert das Grundprinzip von Semaphoren?
Es wird nicht mehr eine Art Sperrvariable
verwendet, sondern ein Zähler. Für dieses Zähler gibt es
die Operationen up(s) bzw. V und down(s) bzw. P zum
Erhöhen bzw. Dekrementieren des Zählers. Ist nach einem
down(s) der Zähler null, wird gewartet. Ist er
irgendwann wieder größer als null werden die Anweisungen
ausgeführt. Der Semaphor ist nun nichts weiter als
dieser Zähler, welcher nur durch up und down ansprechbar
ist! Die beiden Operationen P und V stellen natürlich
auch kleine kritische Abschnitte dar, welche über
aktives Warten synchronisiert werden. P(sem) //Probiere in kritischen Abschnitt einzutreten
{
if (sem == 0)
sleep(sem); //Prozess auf wartend setzen
sem--;
}
V(sem) //Verlasse kritischen Abschnitt
{
sem++; //Zugang wieder freigeben
wakeup(sem);
}
sleep und wakup sind Systembefehle, welche einen
Prozess Schlafenlegen oder Aufwecken.
Prozess A |
Prozess B |
int sem = 1; //zwei Prozesse
|
While (1)
{
P(sem);
// kritischer Abschnitt
V(sem);
}
|
While (1)
{
P(sem);
// kritischer Abschnitt
V(sem);
}
|
|
Wie arbeiten Events bzw. Ereignisse?
Betriebssysteme wie z.B. Unix benutzen Events als
Abstraktion von Semaphoren zum
Koordinieren von Prozessabläufen (im
Gegensatz zu kritischen Abschnitten). Ein Ereignis
stellt nichts weiter als eine für Software erkennbare
Bedingung dar. Ein Prozess kann sich
Schlafen legen, bis eine bestimmte Bedingung eintreten.
- Ein Prozess setzt einen wait()-Aufruf auf ein
Ereignis ab. Er wird dann an dem Event-Deskriptor
wartend gesetzt.
- Wenn an dem Event-Deskriptor das Ereignis
signalisiert wird, so wird ein dort wartender Prozess
bereit gesetzt.
- Der wesentliche Unterschied zu den
Semaphor-Operationen ergibt sich daraus, dass die
Signale nicht gespeichert werden, bei Semaphoren wird
dagegen der Wert bei signal() um 1 erhöht.
Semaphore: Wert 0. Kommt das
signal() vor dem wait(): der wait()-aufrufende Prozess
wird nicht blockiert.
Event: Ein
Wert ist nicht vorhanden, kein Prozess wartet. Das
Ereignis wird vor dem wait()-Aufruf signalisiert: der
wait()-aufrufende Prozess wird blockiert, bis ein
weiteres Ereignis eintrifft. Das erste Ereignis wird
nicht gemerkt.
Was versteht man unter einem Monitor und wie
funktioniert er? Ein Monitor besteht aus einigen
Prozeduren, Variablen und Datenstrukturen die zu einer
besonderen Art Modul zusammengefasst werden. Dieses
Monitormodul verkapselt Semaphore und die Operationen
auf diesen Semaphoren. Nützlichste Eigenschaft eines
Monitors ist, daß jeweils nur ein Prozeß zu einer Zeit
einen Monitor benutzen kann. Ein Monitor ist zwar vielen
Prozessen zugänglich, aber nur jeweils ein Prozeß kann
den Monitor zu einem gegebenen Zeitpunkt benutzen.
Monitore werden häufig zur Verwaltung von Puffern und
Geräten eingesetzt.
- Es gibt dezentrale und zentrale Steuerungen für
kritische Abschnitte
- Dezentrale Steuerungen ist das aktives Warten
- Zentrale Steuerungen sind Semaphore (passives
Warten)
- Beim passiven Warten werden Prozesse
schlafengelegt
- Ereignisse dienen der Koordination
Merktabelle:
Synchronisationsmöglichkeiten
Was ist das Erzeuger-Verbraucher-Problem? Zwei
Prozesse nutzen einen Puffer mit N Plätzen zum
Datenaustausch. Während Prozess A Daten sequentiell in
den Puffer schreibt, entnimmt Prozess B ein Datum aus
dem Puffer.
Nun stellen sich die Fragen
- Wie soll man das gleichzeitige Einfügen und
Entnehmen synchronisieren?
- Ein Datum darf nur eingefügt werden wenn der
Puffer nicht voll ist.
- Ein Datum darf nur eingefügt werden, wenn noch
Platz im Buffer ist.
Gelöst werden, kann das
Problem mit mehreren Semaphoren.
- Ein Semaphor für die Kontrolle des kritischen
Abschnittes
- Ein Semaphor, welcher die freien Plätze zählt
- Ein Semaphor, welcher die vergebenen Plätze zählt
const N 100 //buffer size
int mutex = 1 //Für Kritischen Abschnitt
int empty = N //Anfangs leerer Buffer
int full = 0 //noch keine Daten im Buffer
void ErzeugerProzess()
{
int item;
while(1)
{
iNode = CreateItem();
P(empty);
P(mutex);
Insert(item) //Critical Section
V(mutex); //Mutex wieder erhöhen
V(full); //full=full+1
}
}
void VerbraucherProzess()
{
int item;
while(1)
{
P(full);
P(mutex);
Item = RemoveItem(); //Critical Section
V(mutex);
V(empty);
MakeSomething(Item);
}
}
Der Semaphor mutex verhindert, daß gleichzeitig
Verbraucher und Erzeuger im kritischen Abschnitt sind.
Denn falls der Erzeuger gerade eingetreten ist, ist der
Semaphore mutex null. Versucht nun der Verbraucher in
den kritischen Abschnitt einzutreten, muss er bei
P(mutex) warten, da der mutex noch null ist. Um nun zu
Verhindern das aus einer leeren Liste gelesen oder in
eine volle geschrieben wird, werden hier elegant zwei
weitere Semaphoren verwendet, welche das Vorhandensein
von freien Plätzen (empty) und belegten P lätzen (full)
zählen.
Was ist das Philosophenproblem? Beim
Philosophenproblem geht es nicht um Kommunikation
sondern um Synchronisation. Abstrakt gesehen, gibt es N
Prozesse und N Betriebsmittel. Ein Prozess benötigt
mindestens zwei der Betriebsmittel um fortschreiten zu
können. Ohne Synchronisation, würden im schlimmsten Fall
alle 5 Prozesse je ein Betriebsmittel bekommen und dann
unendlich darauf warten, daß ein anderer Prozess eins
freigibt.
Es sitzen fünf Personen an einem runden
Tisch. Sie können entweder Denken oder Essen. Es gibt
zwar für jeden einen Teller, aber nur fünf Stäbchen. Um
Essen zu können braucht man aber bekanntermaßen zwei.
Wie kann das Philosophenproblem gelöst werden?
Natürlich denkt man zuerst an Semaphoren. Nur
funktioniert die triviale Lösung mit einem Semaphor pro
Stäbchen nicht. Es können immer noch alle Philosophen je
ein Stäbchen gleichzeitig aufnehmen und die Prozesse
wären allesamt verklemmt. Es muss also irgendwie möglich
sein, mehr als ein Stäbchen gleichzeitig aufzunehmen.
Bei den verschiedenen Implementationen ist vor allem
darauf zu achten, daß dieses Aufnehmen der beiden Stäbe
eine Atomare Funktion ist.
Wie funktionieren Unix-Signale? Ein Ereignis
wird hier als Signal bezeichnet. Unter Unix gibt es
vorgegebene durchnummerierte Signale. Unter Unix kann
mit kill(Prozessnummer, Signalnummer) einem
Prozess ein Ereignis signalisiert werden.
Die
Reaktion eines Prozesses auf ein Signal kann verschieden
ausfallen:
- Aktivierung einer Prozessfunktion, die der Prozess
vorher für dieses Signal mit der Funktion
signal( Signalnummer,
Funktionsadresse) angemeldet hat
- Er kann das Signal mit
signal(Signalnummer, SIG_IGN);
ignorieren
- Der Prozess kann beendet werden.
- Hat der Prozess für eine Signalnummer nichts
festgelegt, dann gibt es Voreinstellungen:
|
#define SIGFPE |
8 |
/* Floating point trap */ |
|
#define SIGILL |
4 |
/* Illegal instruction */ |
|
#define SIGINT |
2 |
/* voreingestelle Interrupttaste z.B. Ctl -c*/
|
|
#define SIGSEGV |
11 |
/* Memory access violation */ |
|
#define SIGTERM |
15 |
/* Kill -Kommando ohne Angabe*/ |
|
#define SIGKILL |
9 |
/* unbedingter Prozessabbruch*/
|
Was unterscheidet Pipes und Named Pipes? Pipes
sind nur innerhalb von Prozessgruppen (UNIX) oder
zwischen Threads eines Prozesses verwendbar, da diese
nur dort bekannt ist (und eindeutig identifizierbar).
Diese Einschränkung kann mit der Named
Pipe umgangen werden. Eine Named Pipe ist ein
mit einem eindeutigen Namen versehenes
Objekt des Betriebssystems. Ein Prozess kann
die Pipe erstellen, ein anderer kann eine Verbindung zu
der Pipe herstellen. Im UNIX erhält eine Named Pipe
einen Pfadnamen, wie eine Datei.

Was sind Sockets? Sockets sind im Grunde Pipe
Erweiterungen für Internet und andere Netzdienste. Dabei
werden ein SocketA und ein SocketB zu einer
bidirektionalen Pipe verbunden. Identifiziert wird ein
Socket über Rechneradresse und Portnummer. So
ermöglichen Sie eine
Client-Server-Kommunikation:
Ein Serverprozess
erstellt einen Socket mit create und wartet
dann auf Verbindungswünsche (listen).
Welche Möglichkeiten zur Kommunikation und
Synchronistation kennen Sie?
Kommunikation
- Pipes (FIFO-Puffer - Senden (Schreiben) ist
asynchron, Empfangen (Lesen) blockierend)
- Named Pipes
- Mailboxen (Tool zum Senden und Empfangen von
Nachrichten)
- Send - Receive (BS Unterstützung für Mailboxen -
synchron oder asynchron)
- Queues
- Sockets
- RPC
- Shared Memory
Synchronisation
- Monitore
- Events
- Semaphore
- Barierren (oft zur Threadsynchronisation
verwendet)
|
| |
|
Kapitel 5 - Scheduling
- zentral, dezentral und Modelle für
Scheduling
- Scheduling Strategien
- Prioritätsscheduling und Round Robin
| Scheduling wird
notwendig, wenn die Anzahl der gleichzeitig laufenden
Prozesse die Anzahl der physikalischen Prozessoren
übersteigt. Die Verwaltung kann dezentral (Prozesse
selbst) oder zentral erfolgen. Es gibt zwei grundlegende
Modelle für zentrale Scheduling-Verwaltung:
- Deterministisches Modell - alle Informationen
bekannt (Anzahl Prozesse/Betriebsmittel/Zeitdauer)
- Probabilistisches Modell - offen (Anzahl Prozesse
nicht bekannt) oder geschlossen (Anzahl Prozesse
bekannt, aber Bedienzeiten nicht)
Welche Strategien der Prozessorzuteilung werden
unterschieden?
- Durchsatz (Anzahl bearbeiteter
Prozesse pro Zeiteinheit maximieren)
- Verweilzeit (Prozess soll so
schnell wie möglich abgearbeitet sein)
- Wartezeit (Dauer im Zustand
"wartend" minimieren)
- Effizienz (Prozessorleistung
maximal ausnutzen)
- Antwortzeit (möglichst kurze
Reaktionszeiten für den Benutzer)
- Fairness (gerechte Verteilung der
Prozessorzeit)
Es ist nicht möglich
CPU-Auslastung und Durchsatz zu maximieren und
gleichzeitig Warte- und Antwortzeit zu minimieren.
Deshalb müssen alle Scheduling Algorithmen Kompromisse
eingehen.
Nach welchen Kriterium richtet sich das Scheduling
Verfahren? Dies hängt in erster Linie vom
Einsatzgebiet des Systems ab:
- Echzeitbetrieb
- Dialogbetrieb
- Stabel- bzw. Batchbetrieb
- Hintergrundbetrieb
Was ist das deterministische Modell? Bei diesem
Modell werden die Schedules vor der Ausführung
berechnet. Dies funktioniert natürlich nicht in
interaktiven offenen Systemen, sondern nur in
geschlossenen Systemen mit fester Prozessanahl und
vordefinierter Betriebsmittelnutzung mit statischen
Ablauf. In Dialogsystemen wird deshalb das offene
probabilistische System verwendet, da hier Anzahl der
Prozesse und Betriebsmittelnutzung dynamisch erfolgen...
Was ist das probabilistisches Modell? Die
Entscheidung welcher Prozess den Prozessor bekommt, wird
dynamisch wärend der Prozessabarbeitung gefällt. Hierbei
gibt es einige wichtige Größen, welche als stochastische
Variablen zur Berechnung herangezogen werden können. Die
Warteschlangentheorie ist wichtiges Mittel für
Untersuchungen. (Alle Prozesse welche den Prozessor
fordern werden in eine Warteschlange
eingereiht).

Die Abbildung entspricht einem
Scheduling ohne Prioritäten und ohne Entzug.
Was ist das Single-Server-Modell? Eine
Warteschlange nimmt Prozesse in einem bestimmten Abstand
(A) auf. Der Scheduler entnimmt nach einer gewissen
Wartezeit (W) im Pool einen Prozess und führt diesen in
einer bestimmten Zeit (B) aus .

|
mittlere Verweildauer in
Warteschlange |
W |
Zwischenankunftsabstand |
A |
Prozessorzeit der Teilprozesse |
B |
Anzahl von Prozessen in
Warteschlange |
Nq (N=Nq+p) |
Verkehrswert |
p=B/A (Poisson-Prozesse) |
Verweildauer im System |
V=A*N (Littles Theroem)
|
Weiter Größen wie
durchschnittliche Warteschlangellänge oder die
Wahrscheinlichkeit das sich n Prozesse im System
befinden, lassen sich mit Poissen-Verteilungen genauso
wie die oben erwähnte mittlere Verweildauer ermitteln.
Wie können Wahrscheinlichkeiten für Prozessgrößen
ermittelt werden? Durch Poisson-Prozesse (Markow)
können Erwartungswerte, Mittelwerte und Varianzen für
Zwischenankunftsabstände, Bedienwünsche und Auslastung
berechnet werden. Die Betrachtungen beziehen sich hier
auf den stationären Fall (t->unendlich, also FiFo).
Wie arbeitet First Come First Serve - FCFS?
Ankommende Prozesse werden in eine FIFO Liste
eingereiht und sequentiell abgearbeitet. Somit ist
dieses Modell nicht für Timesharing geeignet, da es eher
eine Batchverarbeitung ist.
Kommt ein langer
Prozess zuerst, müssen andere winzige Prozesse alle auf
die Beendigung des großen Prozesses warten! Unfair.
Bessere Implementationen können deshalb das Token
entziehen.
Durchschnittliche Wartezeit
W = (Wartezeit(P1) + Wartezeit(P2) + ... +
Wartezeit(Pn)) / n
Ist P1 ein vielfach größerer
Prozess als die restlichen, so müssen alle folgenden
Prozesse auf die Beendigung von P1 warten. Dies läßt die
durchschnittliche Wartezeit extrem
steigen.
Bsp.:
t(P1) = 24
t(P2) = 3 t(P3) = 3
Bei einer Abarbeitungsfolge
von P1 -> P2 -> P3 wäre W =
17. Bei einer Abarbeitungsfolge von
P2 -> P3 -> P1 nur 3!
Was ist Prioritäts-Scheduling? Hier wird jedem
Prozess eine Priorität zugewiesen. Ausgewählt wird vom
Scheduler der ausführbereite Prozess mit der höchsten
Priorität. Die Prioritäten können statisch definiert und
dynamisch zugewiesen
werden.
Bsp: FEP
(Fixed External
Priorities)
Was ist das Problem von Schedulern mit Prioritäten?
Hauptproblem beim Arbeiten mit Prioritäten ist das
Aushungern von Prozessen, welche
möglicherweise nie aktiv werden können, da es immer
Prozesse höherer Priorität gibt.
Lösung hierfür
ist das Aging. (dynamische Anhebung der
Priorität der älter werdenden Prozesse)
Ein
anderes Problem ist die Prioritätenumkehr. Ein
hochpriorisierter Prozess wartet auf ein Betriebsmittel,
welches ein niedrigpriorisierter Prozess reserviert hat.
Wie funktioniert Shortest Job First (dynamische
Priorität ohne Entzug)? Es wird der kürzeste Job
zur Verarbeitung ausgewählt. Dabei werden die
Durchlauflängen der einzelnen Prozesse protokolliert.
Nach jedem Prozesswechsel wird die
"bereit"-Warteschlange anhand der Wartezeiten absteigend
neu sortiert.
Deshalb optimiert Shortest Job
First die mittlere Wartezeit. Problem ist hier auch das
Aushungern von Prozessen, was auch durch Aging (Altern)
verhindert werden kann.
SJF ist ohne
Entzug (nonpreemtiv). Eine Variante mit Enzug
ist SRTF. Dabei wird der Prozessor
entzogen, falls ein Prozess in der Warteschlange ist,
der kürzer als der verbliebene Rest des aktiven
Prozesses.
Wie arbeiten Shortest Remaining Time First und
Shortest Elapsed Time (dynamisch mit Entzug)? Diese
beiden Verfahren sind mit Prioritäten und mit Entzug.
Sie sind daher relativ aufwendig, da ein ständiger
Abgleich der Prioritätsdaten erfolgen muss. Bei SET wird
Prozessen, welche schon viel Prozessorzeit zugesprochen
bekamen, die die Prozessorzeit entzogen.
Wie arbeitet Highest Response Ratio Next - HRN?
Umso länger ein Prozess wartet, umso höher steigt
er in seiner Priorität. So wird Aushungern verhindert.
Wie funktioniert Round-Robin Scheduling (ohne
Prioritäten)? Das RR ist die verbreitetste
Strategie, da sie fair ist und sich auch einfach
implementieren lässt. Das Prinzip ist einfach. Jeder
Prozess erhält für eine konstante Zeit t
(Quantum) die Prozessorzeit. Nach
Ablauf des Zeitquantums wird der nächste Prozess aus der
Warteschlange entnommen und bearbeitet. Der zuvor
bearbeitete Prozess wird wieder am Anfang der Liste
eingefügt.
Hauptproblem ist eine sinnvolle
Zeitspanne für das Quantum zu finden. Da bei jedem
Kontextwechsel Register umgeladen müssen, muss ein
gewisser Zeitraum für Verwaltungsarbeiten eingerechnet
werden. Dauert das Umladen der Register 5 ms macht ein
Quantum von 10 ms wenig sinn, da 50% Prozessorzeit
verschwendet werden würde. Wählt man das Quantum aber zu
groß (z.B. 500 ms) so ist im Mehrbenutzerbetrieb nur
bedingte Interaktivität möglich. (RR nähert sich somit
FCFS an)
Sinnvoll erwiesen sich Quanten von
100 ms.
- Scheduling mit oder ohne Entzug
- Scheduling mit oder ohne Prioritäten
- Zentrale Steuerungen sind Semaphore (passives
Warten)
- Beim passiven Warten werden Prozesse
schlafengelegt
- Ereignisse dienen der Koordination
Merktabelle: Scheduling
Algorithmen
Was ist Zweistufiges Scheduling? Angenommen der
Arbeitsspeicher reicht nicht aus, um alle Prozesse
abzubilden, müssen diese auf einen Tertiärspeicher
ausgelagert werden. Da das Auslagern bzw. Einlagern
eines Prozesses sehr viel Zeit in Anspruch nimmt, werden
zwei Stufen benutzt, um das Scheduling zu realisieren.
Die erste Stufe arbeitet nur im Hauptspeicher, während
die zweite Stufe für das Ein- oder Auslagern von
Prozessen verantwortlich ist. Kriterien sind hier
dieselben wie oben schon erwähnt.
- Wie lange ist ein Prozess Aus- oder Eingelagert?
- Wieviel Prozessorzeit hat ein Prozess in Anspruch
genommen?
- Wie groß ist der Prozess im Speicher?
- Welche Priorität hat der Prozess?
Was steht im Widerspruch zu hohem Durchsatz und
guter Auslastung? Im Widerspruch dazu stehen
gutes Antwortzeitverhalten im Dialog-
und Stapelbetrieb. Denn ein hoher Durchsatz und eine
gute Auslastung bedingen viele Prozesse im Rechner, so
daß jeder Prozeß nur relativ selten aktiv werden kann,
d.h. das Antwortzeitverhalten schlechter wird. Auch die
Zuteilungsfairness wird dadurch zunehmend schlechter
bzw. unfairer. |
| |
|
Kapitel 6 - Speichermanagment
- Freispeicherverwaltung durch Bitmaps, Listen
und Buddy
- Mehrdimensionale Adressräume durch
Segmentierung
- virtueller Speicher durch Paging
- Zusammenwirken von Segmentierung und Paging
- Adressumrechnung am Beispiel
| Übersicht zur
Freispeicherverwaltung
Es gibt drei
grundlegende Ansätze zur Verwaltung des freien
Speichers. Diese werden im folgendem Text erläutert.
Was sind Bitmaps? Bitmaps teilen den
Hauptspeicher in gleich große Einheiten und assoziieren
zu jedem Eintrag ein Bit in der Bitmap. Ist der Eintrag
0, so ist der Speicherbereich noch frei. Bei Nutzung
eines Speicherbereiches wird in dem assoziierenden
Bitmapplatz eine eins platziert. Umso kleiner die
zusammengefassten Einheiten werden, umso größer wird die
Bitmap. Der größte Nachteil von Bitmaps ist das Suchen
von freien Speicherbereichen, was eine aufwendige
Operation darstellt.
Welche Möglichkeiten der Suche in Freispeicherlisten
gibt es? Bei dieser Variante werden Listen für
Löcher und belegte Segmente durch Prozesse
geführt.
First
Fit
Der erste freie Block der groß genug
ist wird ausgewählt, egal wieviel Speicher dadurch
verschwendet wird (interne
Fragmentierung).
Next
Fit
Suche beginnt nicht vom Anfang der
Liste, sondern vom zuletzt verwendeten
Listenelement.
Best
Fit
Es wird der optimale Platz in Bezug
auf Speicherausnutzung gesucht. Dadurch das immer Blöcke
mit der geringsten Speicherplatzverschwendung gesucht
werden, werden die freien Blöcke irgendwann zu
klein.
Quick Fit
Es gibt
mehrere Listen für verschiedene Blockgrößen.
Wie funktionieren Buddy Listen? Listen haben
den Nachteil, daß benachbarte freie oder belegte
Speicherbereiche sich nicht zusammenlegen lassen.
Abhilfe schafft hier das Buddy-System. Die Idee beruht
darauf, dass mehrere Listen geführt werden, welche aber
nur Blockgrößen von 2^n zulassen. Zweierpotenz deshalb,
weil ein Rechner Binärzahlen zur Adressierung
benutzt.
Beispiel:
Die
maximale Blockgröße beträgt 64 Mbytes und die minimale
Blockgröße 4 Kbyte. D.h. 226 - 212, also müssen Listen
für N=12 bis N=26 verwaltet werden. Somit wären für
diese Blockgrößenwahl mit dem Buddysystem 15 Listen
notwendig.
Anfragen werden nun immer zur
nächsthöhren Zweierpotenz aufgerundet. D.h. wird eine
Anfrage an einen 75 Kbyte Block gestellt, muss ein 128
Kbyte großer Slot verwendet werden. Anfangs gibt es eine
Liste für in unserem Beispiel 64 Mbyte Speicher. Der
Buddymanager würde die Liste rekursiv so oft teilen, bis
ein 128 Kbyte großer Block in eine der anderen Listen
frei ist.
Falls die angeforderten Blockgrößen
aussschliesslich Zweierpotenzen wären, würde es zu
keiner Internen Fragmentierung kommen können. Da dies
aber nie der Fall ist, wird viel Speicher durch interne
Fragmentierung verschwendet.
Zusammenfassung Freispeicherverwaltung Bitmaps
unterteilen den Speicher in
Allokationseinheiten. Für jede Einheit
gibt es ein Bit im Bitmap. Verknüpfte Listen bieten
Suchmöglichkeiten mit First Fit, Best Fit oder Quick
Fit. Quick Fit setzt mehrere Listen bestimmter Lochgößen
voraus. Das Buddy System verwaltet n Listen von 1,2, 4,
8 bis zur Größe des Speichers. D.h. ein 1 MByte großer
Speicher benötigt 21 Listen und hat Initial nur einen
einzigen Eintrag in der letzten Liste, der das 1 MByte
große Loch beschreibt. Alle anderen Listen sind leer.
Speicher wird nun immer in Abhängigkeit von einer Potenz
von 2 vergeben, der gerade noch groß genug ist, um die
Daten aufzunehmen. Dies wird einfach implementiert, in
dem der Große block einfach solange geteilt wird, bis
der Datenblock in den Freispeicherblock passt. Das
Buddysystem ist zwar schnell, aber impliziert eine
starke interne Fragmentation, da ja
immer auf Zweierpotenzen gerundet werden muss.
- einfache verkettete Listen mit Best-,Next- oder
First-Fit Suche
- Bitmap-System welches Speicher in gleichgroße
Einheiten teilt
- Buddy-Listen nach dem binären System
- Beim passiven Warten werden Prozesse
schlafengelegt
- Ereignisse dienen der Koordination
Merktabelle: Methoden zur
Freispeicherverwaltung
Wie arbeitet Segmentierung (mehrdimensionale
Adressräume)? Eindimensionale Adressierung hat den
Nachteil, daß Programme mit verschieden dynamisch
wachsenden Programmteilen nur schlecht realisierbar
sind. Code, Stack und Daten würden hintereinander im
Speicher liegen. Benötigt ein Programm aber extrem viele
Variablen, würde der Compiler mit der Fehlermeldung
abbrechen, daß es nicht genug Speicher gäbe. Um nun
mehrere Stack, Daten und Codebereiche getrennt
voneinander adressieren zu können, ohne daß die
verschiedenen Teile in Konflikt geraten, wurden die
Segmente eingeführt.
Segmentierte Speicherung
wird oft als das Prinzip der gestreuten
Speicherung benannt. Gestreut deshalb, weil die
einzelnen Seiten nicht nacheinander im Speicher liegen
müssen, sondern dort eingefügt werden, wo Platz ist.
Anders als z.B. bei Kontinuierlicher Allokation, wo viel
Speicher durch externe Fragmentierung verlorengeht,
tritt bei Segmentation dieses Problem nicht auf. Dafür
aber interne Fragmentierung...
Wie werden Segmenten adressiert? Um mit
Segmenten arbeiten zu können, sind zweiteilige Adressen
notwendig, bestehend aus Segment und
Offset. Die Segmentation muss also dem
Programmierer bewusst sein, da ein Segment nur eine
logische Einheit darstellt. Besonders einfach gestaltet
sich das übersetzen von Prozeduren. Angenommen jede
Prozedur hat ihr eigenes Codesegment, benötigt man nur
die Segmentnummer, um die Funktion aufzurufen, da der
Eintrittspunkt bei der logischen Adresse 0 dieses
Segmentes ist. Wird nun eine Prozedur neu kompiliert,
müssen die restlichen Prozeduren nicht neu kompiliert
werden, da der Eintrittspunkt immer noch der gleiche
ist. Und zwar 0. Die Segmentnummern werden eh dynamisch
vergeben.
Was versteht man unter gemeinsam genutzten
Segmenten? Durch Segmentierung wird es sehr
einfach, verschiedene Codesegmente gemeinsam zu nutzen.
So genannte Shared Libraries sind in
jedem modernen Betriebssystem notwendig, denn sie
stellen für viele Programme Frameworks oder API's
bereit, deren Funktionalität sich jedes Programm
bedienen kann, soweit es die dafür notwendigen
Zugriffsrechte hat. Ob ein Segment ausführbar ist oder
nicht, wird über die Schutzart des Segmentes definiert.
Wie funktioniert das Prinzip des virtuellen
Speichers durch Paging? Um mehr Speicher
bereitzustellen werden statt echter physikalischer
Adressen virtuelle benutzt, welche durch die MMU in
reale Adressen bei Benutzung umgewandelt werden. Durch
das Paging können Seiten aus- oder eingelagert (nach
einem Page Fault) werden. Eine Page
Table referenziert virtuelle auf physikalische
Adressen. Swapping ist in Reinform sehr langsam.
Sinnvollerweise werden Segmente in Seiten geteilt,
welche durch Paging ein oder ausgelagert werden.
(Protected Mode) Die MMU kann, muss aber nicht auf der
CPU liegen. Jede Seitentabelleneintrag hat ein
Present/Absent Bit, welches Auskunft darüber gibt, ob
eine Seite sich im Speicher befindet oder nicht. Des
Weiteren vermerkt eine Art Dirty Bit,
ob eine Seite im Speicher geändert wurde, um entscheiden
zu können, ob ein zurück schreiben notwendig
wird.
Die momentan verwendeten Seiten eines
Programmablaufes wird Working Set
genannt. Demand Paging bedeutet, dass Seiten erst dann
abgefordert werden, wenn sie benötigt
werden.
Eine virtuelle Adresse besteht aus
Seitenummer und Offset. Bei einem
Contextswitch wird nach der entsprechenden Seitennummer
in der Page Table gesucht und die zugehörige
physikalische Adresse errechnet. Es wird meist ein
n-stufiges Paging angewandt, um die Suche mach den
Seiten zu beschleunigen (Unix) . Bei i386 gibt es ein so
genanntes Seitenverzeichnis (DIR) mit
1024 Zeilen, welche wiederum je auf eine Seitentabelle
verweisen. Somit enthält eine lineare Adresse beim Intel
DIR,PAGE und OFFSET Teil. (mehrstufiges
Paging)
Beim Swapping werden statt Seiten ganze
Prozesse ausgelagert.
- Demand Paging und Caching basieren auf den
gleichen Prinzip
- Sie arbeiten nur auf verschiedenen Ebenen
- Cache-Misses werden von der Hardware geregelt,
Page Faults vom Betriebssystem
- Beim passiven Warten werden Prozesse
schlafengelegt
- Ereignisse dienen der Koordination
Merktabelle: Virtual Memory und
Caching
Was ist der Translation Lookaside Buffer? Um
die Zeit der Adressumrechnung zu vermindern, wird in der
MMU ein Assoziativspeicher mit meist
nicht mehr als 32 Einträgen verwaltet. Die Einträge
enthalten die zuletzt verwendeten virtuellen Seiten mit
der dazugehörigen Seitenrahmennummer im Speicher.
Gleichzeitig wird dort vermerkt, welche Art von
Lese/Schreibzugriff erlaubt ist und ob die Seite
verändert wurde. Kommt eine Anforderung auf eine nicht
im TLB vorhandene Seite, wird ein Eintrag aus dem TLB
mit der neu dekodierten Adresse überschrieben, so daß
bei der nächsten Anfrage die Adressumrechnung entfallen
kann.
- TLB's werden verwendet, wenn Seitentabelle auf
Grund eines zu großen Adressraumes nicht möglich ist
- TLB bildet zuletzt genutzten (64 bei UltraSparc)
virtuellen Seitennummern auf physikalische
Seitenrahmen ab
- häufig benutzte Seiten werden in einem Cache
(Translation Storage Buffer) verwaltet
- Dieser Cache bildet Seiten direkt ab und wird bei
TLB-Miss zuerst untersucht
- befindet sich die Seite nicht im Cache, muss sie
in der Translation Table gesucht werden
Merktabelle: Translation Lookaside
Buffer
Was sind invertierte Page Tables? Eine
Seitentabelle enthält hier einen Eintrag für jeden
Seitenrahmen des physikalischen Speichers. Der Eintrag
enthält Informationen über den besitzenden Prozess und
die virtuelle Seite. So entspricht die Anzahl der
Einträge der Anzahl der Seitenrahmen im Speicher. Die
Tabelle verwaltet nur, welche Seite, von welchem Prozess
in den Seitenrahmen des Arbeitsspeicher geladen wurden.
Was sind Paging Dämons? Paging arbeitet nur
effizient, wenn jederzeit genügend Seitenrahmen im
Speicher frei sind, um diese bei einem Page Fault neuen
Seiten belegen zu können. Doch wie wird sichergestellt,
daß der Speicher komplett ausgefüllt werden muss und
somit bei einem Page Fault erst eine Seite ausgelagert
werden muss? Viele Betriebssysteme haben dafür einen
speziellen Dienst vorgesehen. Der Paging Dämon wird in
zyklischen Abständen aktiviert. Dieser schaut nun nach
ob genügend Frames im Speicher zur
Verfügung stehen. Ist dies nicht der Fall, werden so
viele Seiten wie notwendig mit einem der
Seitenersetzungsalgorithmen aus dem
Speicher entfernt und auf die Platte zurückgeschrieben.
Erklären Sie das Zusammenspiel von Segmentierung und
Paging? Um beide Vorteile (Mehrdimensionalität und
virtuellen Speicher) nutzen zu können, werden in fast
allen modernen Betriebssystemen beide Techniken
angewandt. Dabei wird das Paging
transparent, also für den Programmierer
nicht sichtbar, hinter die Segmentierung geschalten. Auf
dieser Basis bauen sich auch die Adressen dieser
Maschinen auf. Es gibt verschiedene Implementationen von
Segmentierung und Paging. Aber letztendlich haben sie
eines gemeinsam. Die logische Adresse besteht aus
- die Segmentnummer zur Auswahl des richtigen
Segmentdeskriptors und
- den Offset zur Adressierung innerhalb des
Segmentes.
Die Implementierungen unterscheiden
sich nun in der Verwaltung der
Deskriptoren und der Art und Weise wie
die aus Segment + Offset entstandene virtuelle Adresse
über die Page Table auf den realen Speicher projiziert
bzw. umgerechnet wird.
Was passiert wenn Sie ein Programm starten?
- Der Virtual Memory Manager verwaltet den
virtuellen Speicher.
- Bei Programmstart richtet das BS für den Prozess
eine Seitentabelle ein.
- Eine definierte Anzahl Rahmen werden dem Prozess
als Arbeitsmenge zugeteilt.
- Seiten aus dem Read-Only Bereich der EXE werden
direkt geladen und brauchen nicht zurückgeschrieben
werden.
- Read-Write Bereiche werden zuerst direkt aus der
EXE geladen und im Speicher hinterlegt.
- Bei einem Schreib-Bezug wird sie als private Kopie
in die Auslagerungsdatei geschrieben. So können
mehrere Prozesse die selbe EXE im benutzen. (Copy On
Write)
Der VMM von Windows verwaltet mehrere
Listen für:
- freie Seiten, welche mit 0 initialisiert wurden
(zerofilled)
- uninitialisierte freie Seiten, die noch alten
Inhalt haben
- wartende Seiten, die Prozess zugewiesen waren und
nicht modifiziert wurden(standby pages)
- wartende, aber modifizierte Seiten (modified
pages)
- belegte Seiten, welchen einem Prozess zugewiesen /
referenziert sind (valid pages)
- unbenutzbare Seiten, durch z.B. Hardwarefehler
(unusable pages)
Wie arbeitet die Adressumrechnung der Multics?
- mit Segmentnummer wird Segmentdeskriptor
festgestellt
- es wird geprüft, ob die Pagetable des Segmentes im
Speicher ist
- ist sie nicht im Speicher tritt ein Segmentfehler
auf und es erfolgt ein Trap
- ist sie im Speicher wird der Pagetableeintrag für
die angefragte Seite überprüft
- falls Seite nicht im Speicher entsteht Page Fault
- ist Seite im Speicher wird die physikalische
Adresse des Seitenursprungs aus dem Pagetableeintrag
entnommen
- Der Offset wird zur gewonnenen Adresse
hinzuaddiert und die physikalische Adresse ist
berechnet.
(nach
Tanenbaum)
Meist wird ein Assoziativspeicher
verwendet, um die letzten paar Umrechnungen ohne
Verzögerung ausgeben zu können. Ein TLB enthält zwei
Vergleichsfelder für Segmentnummer und korrespondierende
virtuelle Seite und einige zusätzliche Attribute, wie
Schutzattribute, Age oder Referenziert-Bits.
Wie funktioniert die Adressumrechnung beim P2?
Intel Prozessoren besitzen ab dem i386 eine
LDT (local descriptor table) und eine
GDT (global descriptor table). Die
Local Descriptor Tables enthalten die programmeigenen
Segmente, wie Stack-, Code- und Datensegment der
verschiedenen Benutzerprogramme. Die Global Descriptor
Table enthält dagegen die Systemsegmente samt deren des
Betriebssystems , welche erst geladen werden muss. Wird
ein Segmentselektor in ein Segmentregister geladen, wird
der entsprechende Bezeichner aus der LDT oder GDT geholt
und in MMU Registern gespeichert. Ob L- oder GDT kann
dem Selektor entnommen werden, da dort ein Bit für diese
Auswahl reserviert ist. Der Deskriptor besteht nun aus
der Basisadresse des Segmentes, der Größe des Segmentes
und verschiedenen Privilegbits. Es wird nun eine
virtuelle Adresse über Segmenteselektor + Offset
gebildet. Bei deaktiviertem Paging ist nun diese Adresse
die lineare physikalische. Ist aber Paging aktiv wird
die Adresse als virtuell interpretiert und über die
Seitentabelle auf den realen Speicher abgebildet.
Was haben Deskriptoren mit Sicherheit und
Segmentverwaltung zu tun? Jeder Deskriptor in einer
Deskriptortabelle ist mehrere Byte breit und enthält
Beschreibungsinformationen für ein Segment aus dem
linearen Adressraum. Neben der Segment-Basisadresse
(BASE) enthält er das LIMIT, das die Segmentgröße
angibt. Dabei wird durch ein Granularitätsbit
festgelegt, ob das LIMIT direkt als Länge interpretiert
wird (Segmentgrößen bis 1 MB) oder mit dem Wert 4096
multipliziert wird und damit Segmentgrößen bis 4 GB
unterstützt. Der Descriptor-Privilege-Level gibt an, mit
welcher Berechtigungsstufe der Zugriff auf das Segment
erfolgen muss:
- Level 0: Betriebssystem
- Level 1, 2: Betriebssystemdienste, Treiber,
Systemsoftware
- Level 3: Anwendungssoftware
Weitere
Informationen im Deskriptor zeigen an, ob auf das
Segment lesend, schreibend oder ausführend zugegriffen
werden darf und ob es sich um ein System- oder
Anwendungssegment handelt. Ein Present-Bit gibt an, ob
das Segment sich derzeit überhaupt im Hauptspeicher
befindet.
Zusammenfassung von Freispeicherverwaltung,
Segmentierung und Paging Segmentierung wird
genutzt, um statt einen linearen Adressraum (wie beim
virtuellen Speicher), mehrere virtuelle Adressräume
nutzen zu können. Segmentierung wurde entworfen, um
dynamisch wachsende Tabellen besser Handhaben zu können.
Somit ist schafft Segmentierung einen mehrdimensionalen
Adressraum.
Unter Swapping versteht man das
komplette Ein- und Auslagern von Prozessen. Das Swapping
des segmentierten Speichers ist vergleichbar mit dem
Demand-Paging des virtuellen Speichers. Nur das Segmente
unterschiedlich groß sein können. Aus diesem Grund tritt
hier das Problem der externen Fragmentierung
auf.
Um die externe Fragmentierung zu minimieren,
werden die Löcher als verkettete Liste im Speicher
gehalten. Falls ein Segment geladen werden soll, sucht
z.B. Best Fit, dass nächst größere Loch unter allen, wo
das Segment passen würde. First Fit nimmt das Nächste
Loch, welches für das Segment groß genug
wäre.
Neben dem Swapping kann auch Paging zum
Auslagern von Segmenten benutzt werden. Hierbei sind die
auszulagernden Blöcke gleich groß, da die Segmente in
gleich große Seiten eingeteilt werden. Zur Auslagerung
wird das bekannte Demand Paging benutzt. Meist wird eine
Kombination aus Segmentierung und Paging angewandt, bei
der die Adresse aus zwei Teilen besteht. (Segmentnummer
und Offset innerhalb des Segments). Segmente werden also
in Seiten unterteilt. Zur Leistungsverbesserung werden
die zuletzt verwendeten Segment-Seiten- Kombinationen in
einem Assoziativspeicher (TLB) gehalten. Im Gegensatz
zum Paging ist es beim reinen Swapping nicht möglich,
Prozesse auszuführen, die alleine schon nicht in den
Hauptspeicher passen.
Bitmaps unterteilen den
Speicher in Allokationseinheiten. Für jede Einheit gibt
es ein Bit im Bitmap. Verknüpfte Listen bieten
Suchmöglichkeiten mit First Fit, Best Fit oder Quick
Fit. Quick Fit setzt mehrere Listen bestimmter Lochgößen
voraus. Das Buddy System verwaltet n Listen von 1,2, 4,
8 bis zur Größe des Speichers. D.h. ein 1 MByte großer
Speicher benötigt 21 Listen und hat Initial nur einen
einzigen Eintrag in der letzten Liste, der das 1 MByte
große Loch beschreibt. Alle anderen Listen sind leer.
Speicher wird nun immer in Abhängigkeit von einer Potenz
von 2 vergeben, der gerade noch groß genug ist, um die
Daten aufzunehmen. Dies wird einfach implementiert, in
dem der Große block einfach solange geteilt wird, bis
der Datenblock in den Freispeicherblock passt. Das
Buddysystem ist zwar schnell, aber impliziert eine
starke interne Fragmentation, da ja immer auf
Zweierpotenzen gerundet werden muss. |
| |
|
Kapitel 7 - Seitenersetzung
- Seitenersetzungsalgorithmen wie FiFo, LRU...
- Working Sets als dynamische Variante
- Problem der Seitengröße
|
Was sind Seitenersetzungsalgorithmen? Falls
eine Seite angefordert wird, aber kein Platz für deren
Einlagerung im Speicher mehr vorhanden ist, so muss eine
andere Seite entfernt werden. Aber welche? Es gibt nun
verschiedene Ansätze für dieses Problem...
Welcher wäre der beste Algorithmus zur
Seitenersetzung? Dieser ist theoretisch gegeben,
aber nicht umsetzbar. Die Seite die am
spätesten erst wieder verwendet wird,
wird ausgelagert. Da in einem Echtzeitsystem nie
vorhersagbar ist, welcher Prozess wann wie lange aktiv
sein wird, ist diese Strategie nicht umsetzbar... In
einem deterministischen Modell wäre er aber durchaus
denkbar, da dort jeder Schritt eindeutig definiert ist.
Wie arbeitet die Seitenersetzung mit
Not-Recently-Used? Jede Seite bekommt zwei
Statusbits zugeordnet. R wird gesetzt, wenn die Seite
lesend oder schreibend referenziert wurde. M wird
gesetzt, falls die Seite verändert wird. Diese beiden
Bits sind in jedem Seitentabelleneintrag enthalten und
müssen bei jeder Seitenreferenzierung aktualisiert
werden. Die zwei Bit stellen vier Klassen dar, welche
genutzt werden um einen Paging-Algorithmus zu
realisieren.
- nicht referenzierte und nicht modifizierte Seite
- nicht referenzierte und modifizierte Seite
- referenzierte und nicht modifizierte Seite
- referenzierte und modifizierte Seite
LRU
wählt zufällig eine Seite aus der kleinstnummerierten
Klasse zum Entfernen aus.
Wie arbeitet die Seitenersetzung mit Fifo - First In
First Out? Es wird eine Liste geführt, welche alle
Seiten enthält. Neue Seiten werden an das Ende der Liste
angefügt. So ist die Liste nach dem Alter der
Seiten sortiert. Der FiFo Paging-Algorithmus
macht nichts weiter, als bei einem Seitenfehler die
älteste Seite zu entfernen, also die Seite, die am
Anfang der Liste steht.
Das Problem an Fifo ist,
daß auch extrem häufig referenzierte Seiten ausgelagert
werden. Um dies zu umgehen wird das oben schon erwähnte
R (Referenziert) Bit verwendet, um jeder Seite eine
zweite Chance zu geben, falls das R-Bit nicht null ist.
Wie arbeitet die Seitenersetzung mit Second Chance?
Arbeitet wie Fifo, nur wird beim Entfernen des
Kopfes nachgeschaut, ob das R Bit null ist. Wurde die
Seite nie referenziert, so wird sie entfernt, wie für
FiFo üblich. Wurde sie aber referenziert, wird sie zum
Ende der Liste verschoben, als wurde sie neu geladen.
Das R-Bit wird dabei auf Null gesetzt. So wird
gewährleistet, das häufig benutzte Seiten weniger oft
als nicht referenzierte Seiten ausgelagert werden.
Second Chance ist ein durchaus guter Paging Algorithmus
mit einem Nachteil. Es müssen ständig konstante Seiten
innerhalb der Liste von Anfang zum Ende verschoben
werden. Diesen Nachteil bügelt der Uhr Algorithmus aus.
Wie arbeitet der Uhr-Seitenersetzungsalgorithmus?
Der Clock-Algorithmus arbeitet im Prinzip wie
Second Chance, nur das anstelle einer FiFo Liste eine
Ringliste verwendet wird. Dabei wird in
einem Pointer (Zeiger der Uhr) auf den aktuellen Anfang
der Liste gezeigt. Bei einer Second Chance muss nun
nicht die Seite verschoben werden, es wird einfach der
Zeiger auf das nächste Element referenziert.
Der
Uhr Algorithmus ist also eine Implementation von Second
Chance mit einer Ringliste.
Wie arbeitet die Seitenersetzung mit
Least-Recently-Used? Dieser Paging Algorithmus
versucht den Optimalen zu approximieren, indem es
versucht die Seiten zu entfernen, welche am Längsten
nicht mehr benutzt wurden.
Die Implementation ist
trotzdem nicht ganz einfach. Es müsste theoretisch eine
Liste geführt werden, welche nach dem oben genannten
Kriterium sortiert ist. Diese Liste müsste nach jeder
Seiteneinlagerung neu Sortiert werden. Da dies eine zu
komplexe Operation darstellt, muss dafür eine
Softwarelösung approximiert werden, welche wesentlich
schneller arbeitet.
Wie arbeitet die Seitenersetzung LRU mit
Matrixumsetzung? Es wird eine globale N x N Matrix
für alle N Seiten geführt. Diese Matrix wird mit 0
initialisiert. Wird eine Seite x referenziert, so wird
die Zeile x auf 1 gesetzt und danach die Spalte x auf 0.
In jedem Moment ist die Zeile deren Summe am Kleinsten
ist, die am wenigsten genutzte und die Zeile mit dem
größten Wert, die am häufigsten genutzte
Seite.
Wenn die notwendige Hardware (Matrix)
nicht vorhanden ist, muss ein anderer effizienter Paging
Algorithmus benutzt werden, der ohne jede Hardware
auskommt.
Wie arbeitet die Seitenersetzung NFU - Not
Frequently Used? Bei jeder Uhrunterbrechung wird
das Referenziert-Bit jeder Seite auf
einen Softwarezähler, welcher mit null initialisiert
wurde, hinzuaddiert. Es wird also versucht zu
zählen, wie oft eine Seite referenziert wird.
Das Problem von NFU ist es, dass Spitzen in der
Referenzierung starke Auswirkungen auf den Zähler haben.
So kann es vorkommen, daß eine Seite, welche anfangs
stark genutzt wurde und später nicht mehr, einer
zyklisch genutzten Seite nicht zur Auslagerung
vorgezogen wird.
Eine Modifikation von NFU
versucht LRU zu simulieren und diesen Fehler aufzuheben.
Wie arbeitet die Seitenersetzung mit Aging - LRU
durch Softwareemulation?
- Vor der Addition es Referenziert-Bits werden alle
Zähler um eins nach rechts geschoben
- das Refenziert-Bit wird auf das am weitesten links
stehende Bit addiert
Bei einem Seitenfehler
wird auch hier die Seite mit dem kleinsten Fehler
entfernt. Durch das Rechtsverschieben verkleinert sich
der Wert eines Zählers rapide und es wird verhindert,
daß nur kurzeitig verwendete Seiten fälschlicherweiße
als oft referenziert angesehen werden...
- Not-Recently-Used (referenziert und modifiziert
Bits - vier Zustände)
- Least-Recently-Used (Seiten die lange nicht
benutzt worden auslagern) und LRU mit Matrixumsetzung
- FiFo, Second Chance,
Uhr-Seitenersetzungsalgorithmus
- Aging - LRU durch Softwareemulation
- befindet sich die Seite nicht im Cache, muss sie
in der Translation Table gesucht werden
Merktabelle:
Seitenersetzungsalgorithmen
Was sagt die Belady's Anomalie? Eine Erhöhung
der Seitenrahmen im Speicher, also mehr Speicher, heißt
nicht zwangsläufig eine Verringerung von Seitenfehlern!
Was passiert beim Einsatz einer schnelleren Platte
mit der Seitenfehlerrate? Die Seitenfehlerrate
steigt, da die Übertragungszeit für Seiten sinkt. Die
Anzahl der gleichzeitig ausführbaren Prozesse steigt, da
jeder Prozeß nun mit weniger Seitenrahmen - und einer
höheren Fehlerrate - "leben" kann.
Was sind Working Sets - dynamisches
Seitenaustauschverfahren? Prozess Arbeitsbereiche
werden eingesetzt und die Zahl der Seitenfehler weiter
zu minimieren. Ein Prozess unterliegt auch einer Art
Lokalität. Es werden im Mittel
bestimmte Seiten häufiger und Andere sogut wie nie oder
gar nicht zur Prozessabarbeitung benötigt. Man nennt
dies Referenzielle
Lokalität.
Mit Arbeitsbereichen wird
versucht Informationen vor dem Laden eines Prozesses
auszunutzen, um häufig verwendete Referenzen bevorzugt
zu behandeln. Die Erfassung der für das Working Set
notwendigen Daten wird auch über eine Art Aging
Algorithmus umgesetzt. Jede Seite gehört zu einem
bestimmten Working Set. Wird eine Seite länger als N
Ticks nicht mehr benutzt, wird sie aus dem Working Set
entfernt.
Die gewonnene Information des Working
Sets kann verwendet werden, um den Clock
Algorithmus zu verbessern. Und zwar wird nicht
nur nach einer nichtreferenzierten Seite geschaut,
sondern auch ob die Seite zu einem Working Set gehört
oder nicht. Falls sie einem Arbeitsbereich angehört,
wird sie übersprungen, egal ob im
Moment referenziert oder nicht.
Welche Problematik tritt bei der
Arbeitsmengenstrategie auf? Das Hauptproblem ist
die Seitenauslagerung durch Herausfallen von Seiten aus
dem Working Set. Seiten können aus dem Working Set
ausgelagert werden, ohne das ein Seitenfehler vorliegt
und ohne das für diese Seite eine Neue eingelagert
wurde. Die aktuelle Lokalität wird eben nur
approximiert. Die Arbeitsmenge enthält möglicherweise
auch Seiten die nur einmal benutzt wurden. Der Übergang
zu einer neuen Lokalität erfolgt nur allmählich.
Welche Gefahr besteht bei Seitenaustauschverfahren?
Gefahr des Seitenflatterns
(Trashing). Bei Überlastung mit zu vielen Prozessen die
entweder zu viele Pagefaults produzieren und/oder
zuwenig Seitenrahmen zur Verfügung haben, ist der
Rechner weitgehend mit dem Ein-/und Auslagern von Seiten
beschäftigt und kann an den eigentlichen Aufgaben der
Prozesse kaum noch weiterarbeiten. Effektive CPU
Auslastung sinkt durch viele Seitenfehler. Weitere
Gefahr besteht dann durch zu einfach konstruierte
Scheduler, die bei sinkender CPU-Auslastung mit einer
höheren Prozessintensität reagieren. Page
Damons können dem Abhilfe schaffen, weil sie
Prozesse auslagern, wenn nicht mehr ausreichend
Seitenrahmen im Speicher zur Verfügung stehen.
Was kann man gegen Trashing (Seitenflattern) tun?
Page Dämons benutzten, denn dadurch wird die Anzahl
der gleichzeitig aktiven Prozesse verringert und jedem
Prozeß stehen mehr Seitenrahmen zur Verfügung.
Wie wird die Seitengröße festgelegt? Die
Seitengröße ist normalerweise klein. Dies hat
verschiedene Gründe sie klein zu halten, aber auch einen
wichtigen Grund, die Größe nicht zu klein zu definieren.
Im Mittel ist die letzte Seite eines Codestückes nur
halb gefüllt, da logischerweise nicht
jedes Code, Stack oder Datensegment genau in eine Seite
passen kann oder sich so auf mehrere verteilt, daß kein
freier Speicher mehr verbleibt. Des Weiteren muss
beachtet werden, dass es auch viele kleine Segment gibt.
Angenommen man legt eine Seitengröße von 32 KB fest, so
werden bei 4 KB großen Segmenten stets 28 KB
verschwendet. Andersherum benötigt man mit kleinen
Seiten eine größere Seitentabelle, deren Anzahl
proportional zur Seitengröße ist. Des Weiteren muss man
einkalkulieren, daß das Einladen einer Seite von Platte
eine langwierige Operation ist. Es ist trivial das das
Einlagern von vier 8K-Seiten schneller ist, als das
Einlagern von 64 512 Byte großen Seiten. Es muss also
ein Mittelweg gefunden werden, welcher einen optimalen
Nutzen aus den oben genannten Kriterien
zieht.
Verschwendung = Prozessgröße *
Seitentabelleneintragsgöße / Seitengröße + Seitengröße /
2
Die Nullstellenberechnung der ersten
Ableitung in Abhängigkeit der Seitengröße ergibt
:
Optimale Seitengröße =
Wurzel aus 2 * Prozessgröße * Seitentabelleneintragsgöße
|
| |
|
Kapitel 8 - Deadlocks
- notwendige und hinreichende Bedingung
- Deadlock-Erkennung und Vermeidung
- Bankieralgorithmus
|
Was sind die notwendigen Bedingungen für Deadlocks?
- Mutual Exclusion (z.B. via
Druckerspooler über Ersatz-BM Buffer aufgelöst)
- Belegungs- und Wartebedingung
(Prozess kann weitere BM anfordern)
- Unterbrechbarkeitsbedingung (BM
können nicht entzogen werden)
- zyklische Wartebedingung (Zyklus
im Betriebsmittelgraph)
Was sind die hinreichende Bedingungen für Deadlocks?
Es darf keine externe Betriebsmittelinstanz
bestehen.
Was ist ein Livelock? Es wurde ein
Betriebsmittel vergeben, es besteht aber keine
Verhinderung. Das BM könnte irgendwann wieder
freigegeben werden, aber der Zeitpunkt
unbekannt.
Z.B.
Priotitätsscheduling (langwierige
Prozesse verhungern da benachteiligt)
Wie kann man Deadlocks auflösen oder umgehen?
- Vogel-Strauß Algorithmus (einfach Ignorieren)
- Versuchen zu Erkennen und zu beheben (Topologische
Sortierung des BM-Graphs oder Vektoren-Matrix
Variante)
- dynamisches Verhindern (vor Zuteilung auf Deadlock
prüfen)
- konzeptionelles Vermeiden (eine der notwendigen
Bedingungen eliminieren)
Welche Prozesse sind an einem Deadlock beteiligt?
Prozesse die mehrere Betriebsmittel mit jeweils
exklusiven Zugriff benötigen.
Wie kann man Deadlocks (im Voraus) erkennen?
Die zur Ausführung eines Prozesses notwendigen
Betriebsmittel müssten vor Ausführung bekannt sein. Das
ist aber in einem offenen System nicht möglich. Das
Prinzip ist das gleiche wie das
Preclaiming im DBMS. Erst wenn alle
angeforderten Betriebsmittel verfügbar sind, führt der
Prozess den nächsten Schritt aus. Algorithmisch wäre
dies durch zyklische Prüfung (für jeden Prozeß) auf
Vorhandensein der erforderlichen Betriebsmittel
erreichbar.
Wie werden Deadlocks beseitigt? Durch
Abbruch der beteiligten Prozesse und
Freigabe der belegten Betriebsmittel. Siehe
optimistische Sperrverfahren bei DBMS.
Wie können Deadlocks vermieden werden?
Möglichkeit 1
Es müsste bei jeder
Betriebsmittelanforderung geprüft werden, ob diese zu
einem Deadlock führen würde. Da dies sehr aufwendig ist,
wird so nicht verfahren.
Möglichkeit
2:
Bei Anforderung zusätzlicher
Betriebsmittel werden alle bisher reservierten
Betriebsmittel freigegeben und dann zusammen mit den
zusätzlichen Betriebsmitteln erneut angefordert (Form
von Preclaiming).
Möglichkeit
3
Betriebsmitteltypen werden linear nach
Priorität angefordert . Falls schon Betriebsmittel
reserviert sind, können keine Betriebsmittel, die
wichtiger sind als die schon reservierten, angefordert
werden. Damit wird zyklisches Warten unmöglich (ähnelt
dem 2-Phasen-Sperrprotokoll). Problem ist aber die
Vergabe geeigneter Nummerierungen, da reale und
abstrakte Betriebsmittel (z.B. Spoolbereiche auf
Festplatten) sich nur schwer Ordnen
lassen.
Möglichkeit 4 Der Banker
Algorithmus als Verfahren zur Erkennung sicherer
Systemzustände bei der Verteilung von Ressourcen.
Wie arbeitet der Bankieralgorithmus? Ein Banker
hat einen bestimmte Menge einer Ressource. Jeder Kunde
hat ein Limit, bis zu dem er Ressourcen vom Banker
erhalten kann. Der Banker hat aber so viele Ressourcen,
daß er das größte vorhandene Limit gerade noch bedienen
kann. Der Kunde bekommt die Ressource, falls der Banker
danach noch genügend Ressourcen hat, um mindestens einem
der Kunden sein komplettes Limit zuteilen zu
können.
Beispiel
Bankieralgorithmus
Der Banker habe 10
Einheiten eines Betriebsmittels verfügbar.
- Das Limit von Kunde A betrage 8 Einheiten.
- Das Limit von Kunde B ist 7 Einheiten.
- A hat zur Zeit 5 Einheiten belegt
- und B hat 2 Einheiten reserviert
Falls B
nun eine weitere Einheit anfordert, so muss dies
verweigert werden, da dann der Banker nur noch 2
Einheiten übrig hätte, diese aber nicht zur Befriedigung
einer kompletten Reservierung von A oder B ausreichen
würde und zu einem Deadlock führen würde. Solch ein
Zustand heißt unsicherer Zustand. Der Problem ist nun,
daß jeder Prozeß muß im Voraus wissen muss, wieviele
Einheiten eines Betriebsmittels er maximal während
seiner Abarbeitung benötigen wird.
Warum funktioniert die Deadlock-Vermeidung bei
linearer Ordnung der Betriebsmittel? Prozesse
können zwar alle Betriebsmittel anfordern, aber alle
Anforderungen müssen gemäß der Nummerierungsreihenfolge
geschehen. Somit ist es von vornherein ausgeschlossen,
daß ein Prozeß der ein Betriebsmittel höherer Ordnung
besitzt, ein Betriebsmittel niedrigerer Ordnung, das von
einem anderen Prozeß belegt ist, anfordern kann. Also
werden Schlingen im Wartegraph und damit Deadlocks
vermieden, da nun eine notwendige Voraussetzung für
Deadlocks eliminiert wurde. Umgesetzt kann das Ganze
durch eine Nummerierung der Betriebsmittel werden. Das
Prinzip ähnelt dem Zeitstempelverfahren bei DBMS. |
| |
|
Kapitel 9 - Dateisysteme
- Freispeicherverwaltung
- Verschiedene Dateisysteme wie NTFS
- Dateideskriptoren
- Was sind I-Nodes?
| Hier geht es im
Besonderem um Verwaltung, Zugriffsoptimierung und die
Umsetzung einer für den Menschen vereinfacht nutzbaren
Abstraktion. Der Zugriff auf Daten erfolgt nicht wie
beim Hauptspeicher Byte-orientiert, sondern aus
Effizienzgründen blockweise, da Platten um ein
vielfaches langsamer als Arbeitspeicher sind. Des
Weiteren sind bis auf einige Ausnahmen, wie CD ISO9660,
die meisten Dateisysteme Betriebssystemspezifisch.
Was ist eine Datei? Eine Datei ist ein
logisches Betriebsmittel, welches eine endliche Menge
zusammengehöriger Daten beinhaltet. Verzeichnisse sind
spezielle Dateien, welche zur Strukturierung von
Dateisystemen eingeführt wurden.
Welche Möglichkeiten der Freispeicherverwaltung von
File Systemem gibt es?
- Kontinuierliche Allokation - schlecht wenn Datum
angehangen werden soll
- Verkettete Listen - schlecht, da Wahlfreier
Zugriff extrem langsam
- Listen mit Zuordnungstabellen - Zuordnungstabellen
erlauben schnellen wahlfreien Zugriff (FAT)
- Indizierte Speicherung
- Indirekt indizierte Speicherung
Ein leeres
Dateisystem wird als lineares Medium betrachtet und nach
und nach linear aufgefüllt. Vorteil dieser Variante ist
schneller Zugriff. Nachteil ist die extreme externe
Fragmentierung bei Änderungen von Dateigrößen.
Wie funktioniert das Prinzip der Verketteten Listen?
Listen sind langsamer als kontinuierliche
Allokation, bieten nur wahlfreien Zugriff und besitzen
nur geringe Fehlertoleranz. Dafür werden aber nur sehr
wenig Verwaltungsdaten benötigt. (Hier
nur Pointer auf den nächsten belegten Block) Eine
Verbesserung der Effizienz wird durch das Nutzen doppelt
verketteter Listen erzielt, wobei sich aber auch der
Zahl der Verwaltungsdaten verdoppelt.
Wie funktioniert das Prinzip der Listen mit
Zuordnungstabellen Hier werden die Nutzdaten von
den Zeigern in eine extra Tabelle ausgelagert. Die
Dateizuordnungstabelle am Bsp. FAT enthält für jeden
Block einen Eintrag mit einem Verweis auf den Folgeblock
oder einen bestimmten Eintrag für EOF. Die Effizient
wird hier bei großen Tabellen eingeschränkt.
Wie funktioniert indizierte Speicherung Für
jede Datei wird hier die Startadresse und die Indexlänge
gemerkt. So ist zwar schneller wahlfreier Zugriff
möglich, aber es herrscht das gleiche Problem der
externen Fragmentierung wie bei kontinuierlicher
Allokation. Die Geschwindigkeitssteigerung gegenüber
Zuordnungstabellen kommt daher, dass Zusammenhängende
Blöcke in Zuordnungstabellen nicht hintereinander
liegen, sondern verstreut in der Tabelle. Die indizierte
Speicherung führt sogenannte Indexblöcke ein, in welche
hintereinander die zur Datei gehörigen Blocknummern
eingetragen werden. So muss bei einem Zugriff im Worst
Case nicht die ganze Zuordnungstabelle nach den
Blocknummern durchsucht werden.
Wie groß sollte
nun aber so ein Indexblock gewählt werden? Variable
längen sind schlecht realisierbar. Wählt man sie zu
groß, geht Speicher durch interne Fragmentierung
verloren. Wählt man sie zu klein, beschränkt man die
Dateigröße... Deshalb wurde die indirekt indizierte
Speicherung eingeführt.
Wie funktioniert indirekt indizierte Speicherung
Ein Eintrag im Verwaltungsblock (Indexblock) zeigt
wieder auf einen oder mehrere Blöcke, die nun die
Verweise auf die wirklichen Datenblöcke enthalten, oder
wiederrum auf weitere Indexblöcke. (Dreifach Indirekt)
So ist auch auf große Dateien der Zugriff gewährleistet.
Was ist das Besondere an Unix FS Ext 2? Es
werden Inodes für den Zugriff auf Datenblöcke verwendet.
Die Dateinamen werden in einer extra Tabelle verwaltet,
welche die Attribute (Eigentümer, Zeiten, Größe) und 12
direkte Zeiger auf Blockadressen (einfach, doppelt,
dreifach indirekt) enthält.
Welche Festplatten Scheduling-Algorithmen kennen
Sie?
- First Come First Serve
- Shortest Seek Time First (Sektor mit kürzesten
Suchzeit suchen)
- Scan (Diskarm bewegt sich von einem Ende zum
Anderen und bearbeitet Requests)
- C-Scan (Diskarm wird bei Erreichen des Endes
wieder auf Anfang zurückgesetzt - kreisförmig)
- Look (Wie C-Scan, nur wird nur so weit wie
notwendig zurückgesetzt)
- Look (Wie C-Look, nur kreisförmig)
Welche Bewertungskriterien für
Festplattenalgorithmen gibt es?
- Caching
- Demand Paging wichtiger als E/A der Anwendungen
- Robustheit nach Systemabstürzen
- Berücksichtigung der hohen
Rotationsgeschwindigkeiten moderner Platten
- Verzeichnisse und Indexblöcke sollten in mittleren
statt äußeren oder inneren Zylindern sein, da dort die
mittlere Zugriffszeit am kleinsten ist (im
Durchschnitt befindet sich der Lesekopf in der Mitte)
Wie arbeitet FAT - File Allocation Table? Die
FAT Dateizuordnungstabelle liegt auf den ersten Spuren
einer Platte. Sie wird aus Sicherheitsgründen oft
gesichert. Alle Blöcke einer Platte sind über die FAT
miteinander verkettet (abgesetzte verkettete
Allokation). Die Größe einer Zuordnungseinheit
ist für eine Partition statisch, kann sich aber zwischen
den Partitionen unterscheiden (üblich sind 512, 1024
oder 4096 Bytes). FAT bietet weder Schutzmechanismen,
noch unterstützt es lange Dateinamen (erst ab VFAT).
Welche Verzeichniseinträge hat FAT?
- Dateiname (8+3 Zeichen)
- Attribut-Byte
- Zeit und Datum der letzten Bearbeitung
- Erste Zuordnungseinheit der Datei
- Dateilänge
Das Dateisystem assoziiert eine
Baumstruktur. Für jede Datei enthält die
Dateizuordnungstabelle eine lineare, gezeigerte Liste,
mit der die Blöcke der Datei bzw. des
Unterverzeichnisses bestimmt werden können. Der Index
der Tabelleneinträge stellt die Blocknummer der
Festplatte dar.
Wie arbeitet NTFS? NTFS heißt New Technology
File System. NTFS ist mit einem
Zugriffsschutz ausgestattet und hat
auch keine Größenbegrenzung mehr. Ein Logfile wird
verwendet, um nach einem Systemausfall Daten
rekonstruieren zu können. NTFS besitzt nur Dateien.
Analog zu den I-Nodes beim Unix gibt es beim NTFS eine
Master File Table, in welcher jede
Datei einen Eintrag besitzt. Zusammenhängende Bereiche
(extents) werden als B-Baum
organisiert.
Was ist die MFT von NTFS? Bei kleinen Dateien
bzw. Verzeichnissen werden alle Attribute (incl. der
Daten) innerhalb des MFT-Eintrages abgelegt (bis zu 1
bis 4 KB). Ein Eintrag in der MFT benötigt einen oder
mehrere Sätze der MFT (Satzlänge ist konfigurierbar).
Bei großen Dateien enthält der MFT-Eintrag den
Wurzelknoten eines B-Baums, dessen
"Blätter" die Verweise auf die zusammenhängenden
Dateibereiche (Extent oder Lauf)
enthalten.
Ähnlich wie die Inode-Tabelle beim
UNIX-System stellt die MFT ein flaches Dateisystem dar.
Über die Verzeichnisse wird darauf die bekannte
Baumstruktur definiert.
Wie werden unter NTFS Dateien eindeutig
identifiziert? Jede Datei ist eindeutig über eine
ID identifizierbar. Diese ID ist die
Satznummer ihres Eintrages in der
MasterFileTable (48 Bit). Zusätzlich
wird eine Folgenummer (16 Bit) angehängt, die bei jedem
Bezug auf den MFT-Eintrag (z.B. beim Öffnen der Datei)
um 1 erhöht wird (für Konsistenzüberprüfungen)
Wie werden unter NTFS Verzeichnisse umgesetzt?
Ein Verzeichniseintrag besteht aus dem Dateinamen,
der ID-Nummer der Datei bzw. des Unterverzeichnisses,
einer Kopie der Update-Zeit und der Dateilänge aus dem
MFT-Eintrag. Verzeichnisse werden nicht wie bei FAT in
einer linearen Liste verwaltet, sondern als
B-Baum.
Welche Spezialdateien hat NTFS?
- MasterFileTable (MFT)
- MFT2: enthält die ersten 16 Einträge der MFT als
Backup
- Eine Logdatei (Daten über Transaktionen zum
Wiederherstellen der Daten- bzw. der
Dateisystemkonsistenz)
- Datenträgerdatei enthält den Namen des
Datenträgers, Versionsnummer des Dateisystems und
eventuellen Verdacht auf Inkonsistenz
- Wurzelverzeichnis
- Cluster-Bitmap-Datei für belegte und freie Cluster
des Datenträgers
- Bootdatei mit dem Startcode für NT
- BadClusterDatei, welche Verweise auf defekte
Cluster enthält
Wie arbeiten I-Nodes - Das Unix Dateisystem Die
ersten Adressen von Plattenblöcken sind in dem I-Node
gespeichert. Diese Adressen reichen aber nur für kleine
Dateien aus. Für größere Dateien, welche nicht durch ein
I-Node adressierbar sind, gibt es Adressen in dem
I-Node, die die Adresse eines Plattenblockes enthalten,
welcher weitere Plattenadressen enthält. Dieser Block
wird "einfach indirekter Block"
genannt. "Einfach indirekte" Blöcke verweisen auf
Blöcke, die ihrerseits eine Reihe von direkten
Blocknummern enthalten. Beim Zugriff auf Daten über
einen indirekten Block muß der Kern zuerst diesen
indirekten Block lesen, den passenden direkten
Blockeintrag ermitteln und dann diesen Block lesen. Es
gibt auch Adressen, die auf Blöcke zeigen, die die
Adressen von einfach indirekten Blöcken enthalten.
Solche "doppelt indirekten" Blöcke enthalten eine Liste
indirekter Blocknummern. Blöcke mit dem Kennzeichen
"dreifach indirekt" enthalten eine Liste von doppelt
indirekten Blocknummern u.s.w.

Was sind Dateideskriptoren? Jedem Prozess ist
eine eigene Benutzer-Filedecriptor-Tabelle zugeordnet.
Ruft ein Prozess open oder create holt
der Systemkern einen freien Inode aus der Inode-Tabelle
und übergibt diesen an die globale Dateitabelle und
erzeugt einen Eintrag in der
Benutzer-Filedecriptor-Tabelle.
Was enthält die globale Dateitabelle des Systems?
Den Offset in Byte zum Dateianfang für den nächsten
read- bzw. write-Befehl des Benutzers
und die Zugriffsberechtigungen für den
Prozeß, der die Datei eröffnet hat. Die
Benutzer-Filedecriptor-Tabellen enthalten dagegen nur
die geöffneten Dateien eines Prozesses.

Was beinhaltet ein I-Node?
- Dateityp
- Eigentümer
- Gruppe des Eigentümers
- Zugriffsschutzbits
- Datumseinträge
- Anzahl der Links für diesen I-Node
- Zeiger auf den Dateiinhalt
Geräte als I/O Dateien Es gibt zwei Klassen
solcher Dateien. Blockorientierte Spezialdateien und
Zeichenorientierte Spezialdateien.
Was sind Blockorientierte Spezialdateien?
Blockorientierte Spezialdateien werden benutzt, um
Geräte zu modellieren, die aus frei adressierbaren
Blöcken bestehen. ( random access
devices wie Festplatten). Wird eine
blockorientierte Spezialdatei geöffnet, so kann ein
Block gelesen werden, ohne daß man sich um die Struktur
des Dateisystems, das dies ermöglicht, kümmern zu
müssen.
Was sind Zeichenorientierte Spezialdateien?
werden benutzt, um Geräte zu modellieren, die aus
Zeichenströmen bestehen. Beispiele
hierfür sind Terminals, Drucker, Netzschnittstellen. Ein
Programm schreibt auf das entsprechende I/O-Gerät, indem
es in die korrespondierende zeichenorientierte
Spezialdatei schreibt. Analoges gilt für das Lesen.
Wie ist das Unix Dateisystems aufgebaut?

Der Bootblock ist meistens im ersten
Sektor einer Partition. Er enthält den Bootstrap-Code,
der beim Hochfahren eines UNIX-Rechners in den Speicher
gelesen wird. Er lädt bzw. initialisiert das
Betriebssystem.
Der Superblock
beschreibt den Aufbau des Dateisystems.
Eine Kopie des Superblocks befindet sich permanent im
Speicher. Der Kern schreibt periodisch den Superblock
auf die Platte zurück, so daß er immer mit den aktuellen
Daten im Dateisystem übereinstimmt. Der Superblock
enthält folgende Felder:
- Größe des Dateisystems
- Anzahl der freien Blöcke
- Liste der freien Blöcke
- Index auf den nächsten freien Block
- Größe der I-Nodeliste
- Anzahl der freien Inodes im Dateisystem
- Liste der freien Inodes
- Index auf den nächsten freien Inode in dieser
Liste
- Sperrkennzeichen für die Listen freier Blöcke und
Inodes
- Flag für durchgeführte Änderungen im Superblock
Wie kann ein Prozeß auf Daten auf der Festplatte
zugreifen?
- Das virtuelle Gerät hinter dem die Festplatte
verborgen wird, heißt Datei.
- Der Prozeß öffnet die Datei und erhält eine
Datei-ID die auf eine Datei-Deskriptor-Tabelle
verweist.
- Es folgt die Adressierung der Sektoren.
- Über die Sektoradresstabelle (FAT oder I-Node
Tabelle) werden die Adressen der Blöcke ermittelt
- Es folgt die Übertragung der Blöcke zum
Hauptspeicher
- Zugriff erfolgt nach speziellem Prinzip, wie z.B.
SSN
- zur Minimierung der Suchzeit muss Wahl einer
effizienten Positionierungsstrategie
- Durch einen Interrupt oder ein spezielles Register
teilt der Controller dem BS das Ende der Übertragung
mit.
Wie wird eine Datei unter Unix gesucht? Linux
identifiziert Dateien indirekt über den absoluten
Pfadnamen, indem es durch diesen den dazugehörigen
I-Node sucht. Jede Datei wird durch einen oder mehrere
I-Nodes beschrieben. Die I-Nodes enthalten die
Blockadressen der Datei. Ein Katalog (Verzeichnis)
enthält alle im Verzeichnis enthaltenen Datei- bzw.
Verzeichnisnamen und die dazugehörigen
I-Nodes.
Beispielzugriff:
- Es soll die Datei /var/log/messages
betrachtet werden
- Der I-Node des Wurzelverzeichnisses
"/" steht an einer definierten Stelle
auf der Platte
- Es wird das Verzeichnis "var" im
Wurzelkatalog (auch eine Datei) gesucht
- In diesem Katalog steht der dazugehörige
I-Node der auf das Verzeichnis bzw.
den Katalog "var" verweist
- nun wird in der Katalogdatei "var" nach
"log" gesucht und der dazugehörige
I-Node gelesen
- Nun kann über den I-Node nach dem Eintrag
"messages" in "log" gesucht werden
- Der I-Node der Datei "messages" wird nun in die
globale Dateideskriptortabelle und
die lokale Deskriptortabelle des Prozesses geladen
- Dieser Dateideskriptor ist das
Handle, mit dem der Prozess auf die
Datei zugreifen kann
- Nach eine Close() wird der I-Node
aus der Dateideskriptorliste wieder entfernt.
|
| |
| |
|
Quellen Andrew S. Tanenbaum,
Computerarchitektur Andrew S. Tanenbaum, Moderne
Betriebssysteme Petterson, Computer Architectur &
Design Christian Märtin, Rechnerarchitekturen Kalfa,
Skript und Vorlesung Word Wide Web, Verschiedenste
Seiten
Ausgearbeitet von Holger Kreissl. Online
link
http://www.kreissl.info/diggs/bs_inhalt.php
| | |