docs: add obsidian hwr docs

This commit is contained in:
theoleuthardt 2026-04-09 11:24:56 +02:00
parent b2636f4b92
commit 850aa3455d
245 changed files with 30757 additions and 0 deletions

BIN
Betriebssysteme/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,5 @@
# Klausurvorbereitung
### Themen:
- Operationsprinzipien und Bestandteile eines Minimalsystems bei der John-Von-Neumann Architektur
- Keine Simulation eines Schedulers kommt ran

16
Betriebssysteme/PA.md Normal file
View file

@ -0,0 +1,16 @@
# Notizen zur PA
- C-Datei zu Main (Import von Funktionen)
- C-Datei zu Funktionen
- H-Datei zu Interfaces/**Deklarationen**/Prototypen
Anforderungen genau befolgen!!!
Anforderung:
- wenn eine .c-Datei geändert wird, soll nur die geänderte .c-Datei neu kompiliert werden
- wenn eine .h-Datei geändert wird, sollen alle .c-Dateien neu kompiliert werden
- Test Prints können einfach auskommentiert werden (müssen nicht gelöscht werden, gibt aber auch kein Minuspunkt wenn es keine gibt)
- Jeder Thread soll eine Log-Datei haben
- Ordnungsgemäß warten bis Thread beendet wurden
- Funktionen sollten nur EIN return statement haben
- In Makefile keine Variablen mit $() nutzen sondern Klarnamen der Dateien verwenden!

Binary file not shown.

View file

@ -0,0 +1,148 @@
# Zusammenfassung: Dateisysteme
## 1. Einführung: Warum externe Speicher?
Ein Prozessor kann Informationen nicht dauerhaft in Registern speichern, da diese sich ständig ändern. Auch der Arbeitsspeicher (RAM) ist keine Lösung für langfristige Speicherung, da er:
1. **Flüchtig ist:** Daten gehen beim Ausschalten verloren.
2. **Teuer und begrenzt ist:** Man kann nicht unendlich viel RAM verbauen.
### Gründe für Festplatten/externe Datenträger
- Speicherung sehr großer Datenmengen.
- Dauerhafte Verfügbarkeit (Persistenz) nach dem Herunterfahren.
- Gleichzeitige Nutzung der Daten durch viele Prozesse.
## 2. Definitionen & Grundkonzepte
### Dateisystem vs. Datenbank
Es gibt zwei Hauptarten der Datenspeicherung:
- **Dateisystem:** Das Betriebssystem verwaltet die Daten als Dateien. Es organisiert Speichern, Löschen, Suchen und Umbenennen.
- **Datenbank (DBMS):** Eine separate Software verwaltet strukturierte Daten. (Ausnahme: OS/400 nutzt eine DB als Dateisystem)
### Definition Dateisystem
Es stellt die Regeln dar, wie Daten gespeichert werden. Es sorgt für Transparenz: Der Benutzer muss nicht wissen, wie die Bits physikalisch auf der Platte liegen, er arbeitet nur mit logischen Dateien.
### Klassifizierung von Dateisystemen
1. **Lokal:** Befinden sich auf demselben Rechner (z.B. NTFS auf C:).
2. **Netzwerk:** Befinden sich auf einem anderen Rechner, Kommunikation über OS (z.B. SMB/CIFS).
3. **Verteilt:** Weiterentwicklung von Netzwerk-FS. Der Client weiß nicht, wo physikalisch der Server steht.
4. **Virtuell:** Eine große Datei (Container), die intern wie ein Dateisystem strukturiert ist (z.B. .vhd, .vdi).
## 3. Dateien & Verzeichnisse
### Dateinamen & Konventionen
- **Goldene Regel (Kompatibilität):** Nur lateinische Buchstaben, Ziffern, Unterstrich. Maximal 8 Zeichen. Erstes Zeichen ein Buchstabe.
- **Nicht empfohlene Zeichen:** > < | ? ! * + \ / & ;
### Erkennung von Dateitypen
Das OS muss wissen, ob eine Datei ausführbar ist oder Daten enthält.
1. **Dateierweiterung (für Benutzer):** .exe, .txt, .jpg. Dient der Zuordnung zur Anwendung.
2. **Magische Zahl (für Programme):** Eine Byte-Sequenz am Anfang der Datei:
- **MZ:** Ausführbare MS-DOS/Windows Datei.
- **%PDF:** Adobe PDF Dokument.
- **FFD8 (Start) / FFD9 (Ende):** JPEG Bild.
### Zugriffsarten
- **Sequentiell:** Lesen von Anfang bis Ende (z.B. Magnetbänder).
- **Direkt:** Sprung an eine beliebige Position (Festplatten).
- **Indexsequenziell:** Nutzung eines Index-Blocks, um den richtigen Datenblock schnell zu finden.
### Metadaten (Attribute)
Jede Datei besitzt neben dem Inhalt auch Verwaltungsdaten:
- Eigentümer (User ID).
- Rechte (Read/Write/Execute).
- Zeitstempel (Erstellt, Geändert, Zugriff).
- Flags (Hidden, System, Read-only, Archive).
## 4. Physische Struktur & Partitionierung
Bevor ein Dateisystem erstellt werden kann, muss der Datenträger partitioniert werden.
### Sektoren & Cluster
- **Sektor:** Kleinste physische Einheit der Festplatte (meist 512 Byte).
- **Cluster (Block):** Kleinste logische Einheit des Dateisystems. Besteht aus mehreren Sektoren (z.B. 4 KiB). Eine Datei belegt immer mindestens einen ganzen Cluster (interne Fragmentierung bei kleinen Dateien).
### MBR (Master Boot Record)
Der allererste Sektor der Festplatte.
- Enthält den IPL (Initial Program Loader) zum Booten.
- Enthält die Partitionstabelle (max. 4 primäre Partitionen).
- Adressierung: Zylinder-Kopf-Sektor (CHS). Begrenzt auf 2 TiB.
### GPT (GUID Partition Table)
Der moderne Nachfolger des MBR.
- Teil des UEFI-Standards.
- Adressierung: LBA (Logical Block Addressing) Sektoren werden einfach durchnummeriert.
- Unterstützt Festplatten bis 8 ZiB und (mindestens) 128 Partitionen.
- Enthält einen "Schutz-MBR" für Kompatibilität.
### Boot-Prozess
- **BIOS:** Startet IPL aus MBR. Sehr starr/eingeschränkt.
- **UEFI:** Modernes "Mini-OS" auf dem Mainboard-Chip. Kann Filesysteme lesen, bietet Grafikmenü, Secure Boot.
## 5. Speicherzuweisung (Implementierung)
Wie werden die Blöcke einer Datei auf der Platte organisiert?
### 1. Kontinuierliche Zuweisung
- Datei liegt am Stück (Block 1, 2, 3 hintereinander).
- **Vorteil:** Einfach, sehr schnelles Lesen.
- **Nachteil:** Externe Fragmentierung (Löcher beim Löschen), Datei kann nicht wachsen, wenn kein Platz dahinter ist.
### 2. Verknüpfte Liste (Linked List)
- Jeder Block enthält Daten + Zeiger auf den nächsten Block.
- **Vorteil:** Keine Fragmentierung, Datei kann wachsen.
- **Nachteil:** Zugriff auf Block 500 erfordert Lesen von 1 bis 499 (langsam).
### 3. Informationsknoten (Index / FAT)
- Die Zeiger werden aus den Blöcken herausgenommen und in einer zentralen Tabelle gespeichert.
## 6. Konkrete Dateisysteme
### A. FAT (File Allocation Table)
Das älteste und einfachste System (FAT12/16/32/exFAT).
**Struktur:**
1. **FAT:** Eine Tabelle, die die Festplatte abbildet. Jeder Eintrag entspricht einem Cluster. Inhalte: "Frei", "Defekt", "Letzter Cluster" oder "Zeiger auf nächsten Cluster".
2. **Hauptverzeichnis:** Tabelle mit Dateinamen, Erweiterung, Attributen und Start-Cluster.
3. **Datenzone:** Der eigentliche Inhalt.
**Eigenschaften:** Keine Rechteverwaltung (Sicherheit), kein Besitzer-Konzept, kein Journaling. Dateiidentifikation nur über Name.
**Attribute (8 Bit):** Read-only, Hidden, System, Volume-Label, Directory, Archive.
### B. NTFS (New Technology File System)
Standard seit Windows NT/XP. Proprietär von Microsoft.
- **Struktur:** Zentral ist die MFT (Master File Table). Jede Datei (und das Verzeichnis) ist ein Eintrag in der MFT.
- **Identifikation:** Über FRN (File Reference Number), nicht Name.
**Features:**
- **ACL (Access Control List):** Sehr feine Rechteverwaltung.
- **Journaling:** Protokolliert Änderungen, verhindert Inkonsistenz bei Absturz.
- **EFS:** Verschlüsselung.
- **Quotas:** Speicherplatzbegrenzung pro User.
- **Hard Links:** Ein Inhalt, mehrere Dateinamen (FRNs).
### C. ext (Extended Filesystem - Linux)
Standard unter Linux (ext2/3/4). Verwendet Inodes.
- **Identifikation:** Über Inode-Nummer. Dateinamen existieren nur im Verzeichnis.
**Aufbau:**
- **Superblock:** Infos über FS-Größe und Typ.
- **Bitmaps:** I-Bitmap (belegte Inodes) und D-Bitmap (belegte Datenblöcke).
- **Inode-Liste:** Tabelle aller Inodes.
**Inode-Struktur (Wichtig!):**
Enthält Metadaten (UID, GID, Rechte rwxrwxrwx, Zeitstempel) und Zeiger:
- 12 Direkte Verweise (auf Datenblöcke).
- 1 Indirekter Verweis 1. Grades (zeigt auf Block mit weiteren Zeigern).
- 1 Indirekter Verweis 2. Grades.
- 1 Indirekter Verweis 3. Grades.
- **Resultat:** Sehr kleine und extrem große Dateien (bis Peta-Bytes) effizient speicherbar.
**Verzeichnis:** Ist bei ext einfach eine Datei, die eine Liste von "Name ↔ Inode-Nummer" enthält.
## 7. Fragmentierung & Optimierung
### Interne Fragmentierung
Entsteht, wenn die Dateigröße kein Vielfaches der Blockgröße ist. Der letzte Block ist nur halb voll.
- **Optimierung:** Große Dateien → große Blöcke. Viele kleine Dateien → kleine Blöcke.
### Externe Fragmentierung
Dateien sind physikalisch auf der Platte verstreut (nicht am Stück).
- **FAT:** Stark betroffen.
- **ext:** Bildet Block-Gruppen und lässt Platz für Wachstum → kaum Fragmentierung.
- **xfs:** Puffert im RAM, um Größe zu berechnen, bevor geschrieben wird.
### Bad Blocks
Fehlerhafte Sektoren werden vom Dateisystem markiert und in einen Reserve-Bereich ("Hot Fix") umgeleitet. Das OS bekommt davon nichts mit.
## 8. Sicherheit & Links
### Links (Verknüpfungen)
- **Hard Link:** Ein zweiter Name für denselben Inode/FRN. Löscht man einen, bleibt die Datei erhalten, solange der "Link-Counter" > 0 ist. (Nur im selben FS möglich).
- **Soft Link (Symbolic):** Eine kleine Datei, die nur den Pfad zur Zieldatei enthält. (Funktioniert auch partitionsübergreifend).
### Journaling
Schutz gegen Abstürze während Schreibvorgängen (Stromausfall).
- **Problem:** Metadaten (Bitmap, Inode, Verzeichnis) müssen konsistent sein.
- **Lösung:** Änderungen erst in ein Log (Journal) schreiben, dann ausführen.
- **Full-Journaling:** Auch Nutzdaten werden protokolliert (sehr sicher, aber langsam).
## 9. Backup & Datensicherung
**Wichtig:** Ein RAID-System (Redundant Array of Independent Disks) ist KEIN Backup! RAID schützt vor Hardwareausfall (Verfügbarkeit), Backup schützt vor Datenverlust (Löschen, Virus, Feuer).
### Sicherungsarten (Klausurrelevant!)
1. **Voll-Backup (Normal):** Sichert alles. Setzt das "Archiv-Bit" zurück (markiert als gesichert)
2. **Kopie-Sicherung:** Sichert alles, fasst das Archiv-Bit aber nicht an.
3. **Inkrementell:**
- Sichert nur Änderungen seit dem letzten Backup (egal ob voll oder inkrementell).
- Markiert Dateien als gesichert.
- **Vorteil:** Schnell, klein.
- **Nachteil:** Restore aufwändig (Voll + Ink1 + Ink2 + Ink3 ...).
4. **Differenziell:**
- Sichert Änderungen seit dem letzten Voll-Backup.
- Markiert Dateien nicht als gesichert. Die Sicherung wächst jeden Tag.
- **Vorteil:** Schnellerer Restore (Voll + letzte Diff).
- **Nachteil:** Braucht mehr Platz als inkrementell
### Strategie: Großvater-Vater-Sohn
Rotationsprinzip mit mehreren Medien (z.B. Monat, Woche, Tag). Ermöglicht Rückgriff auf verschiedene Zeitpunkte in der Vergangenheit.
### Betriebsarten
- **Hot Backup:** Im laufenden Betrieb (Gefahr von Inkonsistenz).
- **Cold Backup:** System wird heruntergefahren (Sicher, konsistent).

View file

@ -0,0 +1,82 @@
# Zusammenfassung: Deadlocks (Verklemmungen)
## 1. Grundlagen: Ressourcen und Prozesse
Prozesse benötigen zur Ausführung Ressourcen (Prozessor, Speicher, Dateien, Drucker, Laufwerke). Um das Phänomen Deadlock zu verstehen, muss man zunächst die Art der Ressourcen unterscheiden.
### Arten von Ressourcen
**1. Preemptable (Unterbrechbar/Entziehbar):**
- Diese Ressourcen können einem Prozess weggenommen werden, ohne dass das System abstürzt oder Fehler entstehen.
- **Beispiel:** CPU (durch Scheduling) oder Arbeitsspeicher (auf Standard-PCs durch Paging/Swapping auf die Festplatte).
- **Hinweis:** Auf Smartphones ist RAM oft nicht entziehbar, da diese meist kein Swapping unterstützen.
**2. Non-preemptable (Nicht-unterbrechbar/Nicht-entziehbar):**
- Diese Ressourcen können nicht entzogen werden, ohne dass der Prozess oder die Aufgabe scheitert.
- **Beispiel:** Drucker (ein halb gedrucktes Blatt kann nicht von einem anderen Job fortgesetzt werden), DVD/Blu-ray-Brenner.
- **Fokus:** Deadlocks entstehen meistens im Kampf um diese nicht-entziehbaren Ressourcen.
### Definition eines Deadlocks
Ein Deadlock ist ein Zustand, in dem mehrere Prozesse aufeinander warten. Jeder Prozess wartet auf ein Ereignis (z. B. Freigabe einer Ressource), das nur ein anderer Prozess in dieser wartenden Gruppe auslösen kann. Da alle warten, passiert nichts mehr.
## 2. Die 4 Strategien des Betriebssystems
Wie geht ein OS mit Deadlocks um? Es gibt vier fundamentale Ansätze:
1. **Ignorieren (Ignoring):** So tun, als ob es keine Deadlocks gibt.
2. **Erkennen (Recognizing):** Zulassen, aber erkennen und beheben.
3. **Vermeiden (Avoiding):** Dynamisch zur Laufzeit entscheiden, ob eine Zuweisung sicher ist.
4. **Verhindern (Preventing):** Das System statisch so designen, dass Deadlocks strukturell unmöglich sind.
## 3. Strategie 1: Ignorieren (Der Strauß-Algorithmus)
Dies ist der einfachste Ansatz: Das Betriebssystem ignoriert die Möglichkeit eines Deadlocks komplett. Wenn einer auftritt, bleiben die Prozesse ewig hängen, bis der Benutzer eingreift (z. B. Prozess killt oder neu startet).
### Rechtfertigung
- **Wahrscheinlichkeit:** Wenn Deadlocks sehr selten auftreten (z. B. einmal alle 5 Jahre), aber reguläre Hardware-Abstürze wöchentlich passieren, lohnt sich der Aufwand für eine komplexe Deadlock-Lösung nicht.
- **Performance:** Lösungen kosten oft Leistung oder Komfort. Ingenieure nehmen selten massive Performance-Einbußen in Kauf, um ein extrem seltenes Problem zu lösen.
- Dieser Ansatz ist technisch "falsch", aber wirtschaftlich oft die Realität (Windows, Linux und macOS nutzen diesen Ansatz in vielen Bereichen).
## 4. Voraussetzungen: Die Coffman-Bedingungen
Damit ein Deadlock überhaupt entstehen kann, müssen vier Bedingungen gleichzeitig erfüllt sein (Coffman's Conditions):
1. **Mutual Exclusion (Gegenseitiger Ausschluss):** Eine Ressource darf nur von einem Prozess exklusiv genutzt werden (nicht teilbar).
2. **Hold and Wait (Besitzen und Warten):** Ein Prozess besitzt bereits Ressourcen und fordert weitere an, während er die alten behält.
3. **No Preemption (Nicht-Entziehbarkeit):** Ressourcen können nicht gewaltsam weggenommen werden; der Besitzer muss sie freiwillig zurückgeben.
4. **Circular Wait (Zirkuläres Warten):** Es gibt eine Kette von Prozessen (A wartet auf B, B wartet auf C ... C wartet auf A), die im Kreis aufeinander warten.
## 5. Strategie 2: Erkennung (Recognizing)
Das System lässt Deadlocks zu, überwacht aber den Zustand, um sie zu erkennen und dann zu lösen.
### Der Ressourcengraph
Zur Erkennung baut das OS einen Graphen auf:
- **Kreise:** Stellen Prozesse dar (P).
- **Rechtecke:** Stellen Ressourcen dar (R).
- **Pfeil P → R:** Prozess fordert Ressource an (Request).
- **Pfeil R → P:** Prozess besitzt Ressource (Assignment).
### Analyse
Das OS prüft diesen Graphen mittels Algorithmen (Tiefensuche, Rekursion) auf Zyklen.
- Wird ein Zyklus (Kreis) gefunden, liegt ein Deadlock vor.
- **Beispiel:** P1 hat Kamera, will HDD. P2 hat USB, will Kamera... P5 hat HDD, will USB. Dies bildet einen geschlossenen Kreis → Deadlock.
### Behebung (Recovery)
Wenn ein Deadlock erkannt wurde, muss er durchbrochen werden:
1. **Killing (Prozessabbruch):** Einen Prozess im Zyklus beenden. Brachial, aber einfach. Am besten trifft es Prozesse, die ohne Datenverlust neu gestartet werden können (z. B. Compiler).
2. **Preemption (Entzug):** Einer Ressource temporär den Besitzer wegnehmen. Hängt stark von der Hardware ab und ist oft manuell oder gar nicht möglich.
3. **Rollback (Zurücksetzen):** Prozesse erstellen regelmäßig Checkpoints (Sicherungspunkte des Zustands). Bei Deadlock wird ein Prozess auf einen früheren Zeitpunkt zurückgesetzt (bevor er die kritische Ressource anforderte). Er verliert die Arbeit seit dem Checkpoint, aber der Deadlock ist gelöst
## 6. Strategie 3: Vermeidung (Avoiding)
Hier wird versucht, Deadlocks dynamisch zu umgehen, bevor sie entstehen. Das System entscheidet bei jeder Anfrage: "Ist es sicher, diese Ressource jetzt zu vergeben?"
### Das Konzept des sicheren Zustands
- Ein Zustand ist sicher, wenn es einen Weg gibt, alle Prozesse nacheinander zu bedienen, ohne dass sie blockieren.
- Das OS führt Buch darüber, welcher Prozess was braucht. Droht ein "unsicherer Zustand" (Clinch), wird die Ressource nicht vergeben, und der Prozess muss warten.
### Das Problem
Avoiding funktioniert nur, wenn das OS in die Zukunft sehen kann. Es muss im Voraus wissen:
- Welche Prozesse laufen werden.
- Wann genau sie welche Ressourcen brauchen.
Da diese Informationen in der Realität fast nie vorliegen, ist diese Strategie in der Praxis kaum anwendbar.
## 7. Strategie 4: Verhinderung (Preventing)
Dieser Ansatz ist statisch. Das System wird so designt, dass mindestens eine der vier Coffman-Bedingungen (siehe Punkt 4) niemals erfüllt werden kann. Wenn eine Bedingung fehlt, ist ein Deadlock mathematisch unmöglich.
Man greift gezielt die einzelnen Bedingungen an:
### A. Angriff auf "Mutual Exclusion" (Exklusivität)
- **Idee:** Ressourcen gar nicht exklusiv vergeben.
- **Lösung:** Spooling. Beispiel Drucker: Kein Prozess greift direkt auf den Drucker zu. Nur ein "Drucker-Daemon" darf das. Prozesse schreiben ihre Daten in eine Datei (Spool-Verzeichnis). Da Prozesse nur Dateien schreiben (was parallel geht) und nicht auf den Drucker warten, gibt es keinen Deadlock am Drucker.
### B. Angriff auf "Hold and Wait" (Besitzen und Warten)
- **Idee:** Verhindern, dass jemand Ressourcen hortet und auf neue wartet.
**Lösung 1:** Ein Prozess muss alle benötigten Ressourcen ganz am Anfang anfordern. Bekommt er sie, läuft er. Wenn nicht, wartet er mit leeren Händen.
- **Nachteil:** Man weiß oft nicht am Start, was man später braucht. Ressourcen werden verschwendet (lange belegt, aber erst am Ende genutzt).
- **Beispiel:** Mainframe-Batch-Jobs (JCL) müssen oft alle Ressourcen im Header definieren.
**Lösung 2:** Wer eine neue Ressource will, muss erst alle alten zurückgeben und dann alles zusammen neu anfordern.
### C. Angriff auf "No Preemption" (Nicht-Entziehbarkeit)
- **Idee:** Ressourcen gewaltsam wegnehmen.
- **Problem:** Bei Druckern oder CD-Brennern führt das zu Chaos/Datenmüll.
- **Lösung:** Virtualisierung (siehe Spooling). Die Hardware wird "versteckt", aber das geht nicht bei allen Ressourcen (z. B. Datensätzen in Datenbanken).
### D. Angriff auf "Circular Wait" (Zirkuläres Warten)
- **Idee:** Kreise unmöglich machen.
- **Lösung:** Hierarchische Anforderung.
- Alle Ressourcen bekommen eine Nummer (1 bis N).
- **Regel:** Ein Prozess darf Ressourcen nur in aufsteigender Reihenfolge anfordern.
- Wer Ressource Nr. 5 hat, darf Nr. 6 anfordern, aber niemals Nr. 2.
- Damit ist ein Kreis (A → B → A) mathematisch ausgeschlossen.

View file

@ -0,0 +1,254 @@
# Zusammenfassung Einführung + Hardware
### 1. Definition und Aufgaben
**Hauptaufgabe:** Verwaltung physischer und logischer Ressourcen (CPU, RAM, Geräte, Prozesse)
**Schlüsselkonzept Transparenz:** Das BS verbirgt die komplexe interne Struktur und Hardware-Details vor dem Benutzer
• **Zielfunktionen:**
    ◦ **Auftragsverwaltung:** Steuerung und Abrechnung von Jobs
    ◦ **Betriebsmittelverwaltung:** Zuweisung von Hardware und Vermeidung von Konflikten (Deadlocks)
    ◦ **Speicherverwaltung:** Verwaltung von physischem und virtuellem Speicher
    ◦ **Schutz:** Zugriffskontrolle und Fehlerbehandlung
### 2. Klassifizierung von Betriebssystemen
Betriebssysteme werden nach verschiedenen Kriterien unterschieden:
• **Anzahl der Aufgaben:**
    ◦ **Single-Tasking:** Nur ein Programm läuft (historisch)
    ◦ **Multi-Tasking:** Mehrere Programme laufen scheinbar gleichzeitig
• **Verarbeitungsmodus:**
    ◦ **Stapelverarbeitung (Batch):** Jobs werden ohne Benutzerinteraktion nacheinander abgearbeitet (Großrechner)
    ◦ **Dialogbetrieb (Interactive):** Der Benutzer interagiert direkt mit dem System
    ◦ **Echtzeitverarbeitung (Real-time):** Garantierte Reaktionszeiten für Steuerungsaufgaben
**Architektur:** Zentralisiert vs. Verteilt (Zentrale Systemsteuerung existiert/existiert nicht)
### 3. Eigenschaften moderner Betriebssysteme
**Präemptives Multitasking:** Das BS kann einem Prozess die CPU entziehen (im Gegensatz zum kooperativen Multitasking, wo das Programm die CPU freiwillig abgeben musste)
**Multithreading:** Eine Anwendung kann mehrere Aufgaben (Threads) parallel ausführen
**Symmetrisches Multiprocessing (SMP):** Mehrere gleichwertige Prozessoren teilen sich die Aufgaben ("jeder macht alles")
**Stabilität:** Durch Speichertrennung führt der Absturz einer App nicht zum Absturz des Gesamtsystems
**Sicherheit (C2-Standard):** Authentifizierung, Zugriffskontrolllisten (ACLs) für Ressourcen und Protokollierung
**Skalierbarkeit:** Fähigkeit, Leistung bei wachsenden Anforderungen durch neue Hardware (_Scale Up_) oder neue Rechner (_Scale Out_) zu halten
### 4. Architektur und Design (Kernel)
**Bestandteile eines BS:** Kernel (resident im RAM), externe Module (Treiber), Befehlsinterpreter. _Nicht_ dazu gehören Compiler oder Office-Programme
**Architektur-Modelle:**
• **Monolithischer Kernel:**
    ◦ Alles (Dateisystem, Treiber, Speicherverwaltung) läuft im Kernel-Modus in einer Datei.
    ◦ _Vorteil:_ Sehr schnell.
    ◦ _Nachteil:_ Ein Fehler im Treiber bringt das ganze System zum Absturz
• **Mikrokernel:**
    ◦ Nur minimale Funktionen (IPC, Scheduling) im Kernel-Modus. Treiber und Dateisysteme laufen im Benutzer-Modus.
    ◦ _Vorteil:_ Sehr stabil.
    ◦ _Nachteil:_ Langsamer durch Kommunikations-Overhead
**Hybrid:** Mischung aus beiden (z.B. Windows, macOS), um Geschwindigkeit und Stabilität zu vereinen
**Schichtenmodell:** Jede Schicht darf nur Dienste der direkt darunterliegenden Schicht nutzen
### 5. Dualer Modus
Zum Schutz vor fehlerhaften Programmen arbeitet der Prozessor in zwei Modi (gesteuert durch das CPL-Bit im Register):
1. **Kernelmodus (Ring 0 / CPL=0):** Das BS hat vollen Zugriff auf alle Befehle und Hardware
2. **Benutzermodus (Ring 3 / CPL=3):** Anwendungen laufen hier. Kritische Befehle (Hardwarezugriff, I/O) sind verboten
### 6. Systemaufrufe
**Der Systemaufruf (System Call):** Wenn eine Anwendung eine kritische Operation benötigt (z.B. "Speichere Datei"), kann sie das nicht selbst tun.
• Sie ruft eine Bibliotheksfunktion auf (z.B. `open()`, `read()`)
• Dies löst einen **Systemaufruf** aus.
• Die CPU schaltet in den **Kernelmodus**, führt die Aufgabe sicher aus und schaltet zurück
#### 1. Das Grundproblem
Eine Anwendung (z.B. Word) darf nicht direkt auf die Hardware (z.B. Festplatte) zugreifen. Würde sie das tun, könnte ein Fehler in Word die Festplatte beschädigen oder Daten anderer Programme überschreiben. Daher laufen Anwendungen im **Benutzermodus (User Mode, Ring 3)** und das Betriebssystem (BS) im **Kernelmodus (Kernel Mode, Ring 0)**.
Ein **Systemaufruf** ist der definierte Weg, wie eine Anwendung den Kernel bittet: _"Bitte erledige diese privilegierte Aufgabe für mich"_
#### 2. Der Ablauf eines Systemaufrufs
Der Prozess ist streng geregelt, um Sicherheit zu garantieren:
1. **Aufruf:** Die Anwendung ruft eine Bibliotheksfunktion auf (z.B. `read()` in C),.
2. **Auslöser:** Diese Funktion löst einen Software-Interrupt (Trap) aus. Dies signalisiert der CPU, dass ein Moduswechsel nötig ist.
3. **Moduswechsel:** Die CPU schaltet vom Benutzermodus (CPL=3) in den Kernelmodus (CPL=0),.
4. **Identifikation:** Das BS schaut in einer internen Tabelle (System Call Table) nach, welche Funktion ausgeführt werden soll (basierend auf einer ID/Nummer),.
5. **Prüfung:** Das BS prüft die übergebenen Parameter auf Gültigkeit (z.B.: Darf dieser Nutzer diese Datei lesen?),.
6. **Ausführung:** Der Kernel führt die Operation (z.B. Festplattenzugriff) aus.
7. **Rückkehr:** Das BS schaltet zurück in den Benutzermodus und gibt das Ergebnis (oder einen Fehlercode) an die Anwendung zurück
#### 3. Methoden der Parameterübergabe
Da der Kernel und die Anwendung in unterschiedlichen Adressräumen arbeiten können, ist die Übergabe von Daten (z.B. "Welche Datei soll geöffnet werden?") nicht trivial. Es gibt drei Methoden:
1. **Über Register:**
    ◦ _Funktionsweise:_ Parameter werden direkt in die CPU-Register geschrieben.
    ◦ _Vorteil:_ Sehr schnell und einfach.
    ◦ _Nachteil:_ Die Anzahl und Größe der Register ist stark begrenzt (reicht nicht für viele Daten).
2. **Über einen Speicherblock (Tabelle):**
    ◦ _Funktionsweise:_ Die Parameter werden in einen Speicherblock im RAM geschrieben. Nur die **Startadresse** dieses Blocks wird in einem Register an den Kernel übergeben.
    ◦ _Vorteil:_ Anzahl und Größe der Parameter spielen keine Rolle.
    ◦ _Nachteil:_ Langsamer als Register
3. **Über den Stack (Stapel):**
    ◦ _Funktionsweise:_ Parameter werden auf den Stack gelegt (push). Das BS liest sie vom Stack (pop).
    ◦ _Vorteil:_ Flexible Anzahl an Parametern möglich.
#### 4. Kategorien und Beispiele
Systemaufrufe decken alle Bereiche ab, in denen das BS Ressourcen verwaltet. In den Folien werden folgende Kategorien unterschieden:
| | | |
|---|---|---|
|Kategorie|Beispiele (Funktionen)|Erklärung|
|**Prozessmanagement**|`fork()`, `exit()`, `CreateProcess()`|Prozesse erzeugen, beenden oder steuern.|
|**Dateiverwaltung**|`open()`, `read()`, `CreateFile()`|Dateien öffnen, lesen, schreiben.|
|**Speicherverwaltung**|`malloc()`, `GlobalAlloc()`|Arbeitsspeicher anfordern.|
|**Geräteverwaltung**|`ioctl()`, `ReadConsole()`|Hardware konfigurieren oder ansprechen.|
|**Zeitmanagement**|`sleep()`, `SetTimer()`|Warten oder Zeit messen.|
|**Schutz/Sicherheit**|`chmod()`, `icacls()`|Zugriffsrechte ändern.|
#### 5. Inkompatibilität zwischen Betriebssystemen
Warum läuft ein Windows-Programm (.exe) nicht auf Linux? Einer der Hauptgründe sind die Systemaufrufe.
• Die **Formate** der Systemaufrufe sind unterschiedlich.
• Die **Art**, wie Parameter übergeben werden, unterscheidet sich. Selbst auf der gleichen Hardware (z.B. Intel CPU) sind Anwendungen daher nicht kompatibel, da sie eine "andere Sprache" sprechen, um mit dem Kernel zu reden
### 7. Programmausführung & Speicher
Wie wird aus Code ein Prozess?
1. **Compiler:** Quellcode -> Objektdatei
2. **Linker:** Verbindet Objektdatei mit Bibliotheken -> Ausführbare Datei (.exe)
3. **Loader:** Lädt Datei in den RAM -> **Prozess**
**Speicheraufbau eines C-Programms im RAM:**
**Text:** Der Programmcode
**Data:** Initialisierte globale Variablen
**BSS:** Nicht-initialisierte globale Variablen
**Heap:** Dynamischer Speicher (malloc)
**Stack:** Lokale Variablen und Funktionsaufrufe
## Hardware:
### 1. Grundbegriffe & Einheiten
**EVA-Prinzip:** Eingabe → Verarbeitung → Ausgabe. Peripheriegeräte (Tastatur, Monitor) machen E/A, die Systemeinheit (CPU) macht die Verarbeitung
**Maßeinheiten:** Die Folien unterscheiden strikt zwischen dezimalen und binären Präfixen:
    ◦ **KB, MB, GB:** Basieren auf Faktor 1000 (103).
    ◦ **KiB, MiB, GiB:** Basieren auf Faktor 1024 (210). _Wichtig: Das Betriebssystem rechnet meist binär (GiB), Festplattenhersteller oft dezimal (GB)._
### 2. Rechnerarchitekturen
#### Von-Neumann-Architektur (Standard PC)
Die meisten modernen PCs basieren auf dem **John-von-Neumann-Prinzip** (1945):
1. **SISD:** Single Instruction, Single Data (ein Befehl bearbeitet einen Datensatz).
2. **Gemeinsamer Speicher:** Befehle (Programmcode) und Daten liegen im selben RAM.
3. **Lineare Adressierung:** Speicherzellen werden über Adressen angesprochen.
#### Andere Architekturen
**Harvard:** Getrennter Speicher für Befehle und Daten (schneller, teurer).
**SIMD (Single Instruction Multiple Data):** Ein Befehl bearbeitet viele Daten gleichzeitig (Vektorrechner, Supercomputer).
**MIMD (Multiple Instruction Multiple Data):** Viele Prozessoren bearbeiten unterschiedliche Daten mit unterschiedlichen Befehlen.
#### Das Minimalsystem
Ein funktionierender Computer benötigt mindestens:
1. **CPU:** Verarbeitet Daten.
2. **RAM:** Speichert Daten flüchtig.
3. **Datenträger:** Speichert Daten dauerhaft.
4. **Bussystem:** Verbindet alles. Besteht aus:
    ◦ _Datenbus_ (Prozessor -> Arbeitsspeicher).
    ◦ _Adressbus_ (wählt Speicherzellen/Geräte aus).
    ◦ _Steuerbus_ (Taktgeber, Lese-/Schreibsignale).
#### Mainboard:
Die Hauptplatine belegt die zentrale Stelle im Systemgehäuse. Sie steuert die Zusammenarbeit aller Bauteile
**Wichtige Komponenten auf dem Mainboard:**
**Prozessorsockel:** Hier wird die CPU eingesetzt. Server-Mainboards können oft mehrere Sockel für mehrere Prozessoren haben, um die Leistung massiv zu steigern
**Chipsatz:** Der "Verkehrspolizist" des Mainboards. Er steuert den Datenfluss zwischen Prozessor, Speicher und Peripherie
• **BIOS & CMOS:**
    1. **Das BIOS (Basic Input/Output System)** ist die **Firmware** (Software). Es enthält die unveränderlichen Funktionen und Anweisungen, um den Startvorgang (Boot) überhaupt durchzuführen,
2. **Das CMOS** ist der **Datenspeicher**. Es ist ein kleiner Speicherchip, der die **variablen Einstellungen** (Uhrzeit, Boot-Reihenfolge, Passwörter) speichert. Da dieser Speicher flüchtig ist, wird er von einer kleinen **Batterie** auf dem Mainboard gepuffert, damit die Daten nicht verloren gehen, wenn Sie den Stecker ziehen
**Kurz gemerkt:** Das BIOS ist der „Motor“ (das Programm), das CMOS ist der „Tank“ für Ihre persönlichen Einstellungen.
• **Schnittstellen & Steckplätze:**
    ◦ _Intern:_ Speicherbänke für RAM, Anschlüsse für Festplatten/SSDs (SATA/M.2)
    ◦ _Erweiterung:_ Slots (z.B. PCIe) für Grafik-, Sound- oder Netzwerkkarten
    ◦ _Extern:_ USB, Monitor, Netzwerk
### 3. Der Prozessor (CPU)
Die CPU führt arithmetische und logische Operationen aus. Die Leistung hängt von der Taktfrequenz und der Architektur (32-Bit vs. 64-Bit) ab
#### CISC vs. RISC
**CISC (Complex Instruction Set Computing):** (z.B. Intel/AMD)
    ◦ Mächtige, komplexe Befehle.
    ◦ Befehle werden intern oft durch **Mikrocode** (Software im Chip) realisiert.
    ◦ _Nachteil:_ Dekodierung dauert länger.
**RISC (Reduced Instruction Set Computing):** (z.B. ARM, SPARC)
    ◦ Wenige, einfache Befehle.
    ◦ Fest verdrahtet (kein Mikrocode), sehr schnelle Ausführung.
#### Wichtige Register
Register sind extrem schnelle, aber kleine Speicherbereiche direkt im Prozessor. Sie sind entscheidend für die Arbeitsweise der CPU und das Verständnis von Kontextwechseln (Multitasking).
##### 1. Register-Gruppen und Namenskonventionen
Die Bezeichnung der Register hängt von der Architektur ab. Die Folien nutzen die Intel-Nomenklatur:
**16-Bit:** `AX`, `BX`, `CX` ...
**32-Bit:** `EAX`, `EBX`, `ECX` ... (E = Extended)
**64-Bit:** `RAX`, `RBX`, `RCX` ... (R = Register/Re-extended)
##### 2. Datenregister (General Purpose Registers)
Diese werden für Rechenoperationen genutzt:
**AX / EAX / RAX (Accumulator):** Der primäre Akkumulator für arithmetische Operationen. Er wird auch für den Datenaustausch mit dem Arbeitsspeicher genutzt (ein Operand hier, einer im RAM).
**BX / EBX / RBX (Base):** Das Basisregister. Es wird oft für die adressierte Indizierung (Zeiger auf Daten) verwendet.
**CX / ECX / RCX (Counter):** Das Zählregister. Es ist speziell für Schleifen (`loops`) optimiert, da es automatisch herunterzählen (dekrementieren) kann.
**DX / EDX / RDX (Data):** Das Datenregister. Es wird für I/O-Operationen und für Berechnungen mit großen Zahlen (z.B. Multiplikation/Division zusammen mit AX) genutzt.
##### 3. Segmentregister
Da der Speicher in Segmente unterteilt ist, zeigen diese Register auf den Beginn eines Segments:
**CS (Code Segment):** Startadresse des Programmcodes (Befehle).
**DS (Data Segment):** Startadresse der Daten (Variablen, Konstanten).
**SS (Stack Segment):** Startadresse des Stacks (für Funktionsaufrufe/lokale Variablen).
**ES (Extra Segment):** Zusätzlicher Speicherbereich für Daten.
##### 4. Zeiger- und Indexregister (Klausurrelevant!)
Diese Register sind für den Programmablauf und die Stack-Verwaltung essenziell:
• **IP / EIP / RIP (Instruction Pointer / Befehlszeiger):**
    ◦ Speichert die Adresse des **nächsten** auszuführenden Befehls.
    ◦ Zusammen mit dem `CS`-Register (`CS:IP`) ergibt sich die exakte physikalische Adresse des Befehls.
• **SP / ESP / RSP (Stack Pointer / Stapelzeiger):**
    ◦ Zeigt immer auf das aktuelle **Ende** (Top) des Stacks.
    ◦ Wird zusammen mit dem `SS`-Register (`SS:SP`) verwendet.
• **BP / EBP / RBP (Base Pointer):**
    ◦ Dient als Referenzrahmen für Funktionsparameter und lokale Variablen auf dem Stack.
    
Wenn ein **Interrupt** auftritt oder ein **Prozesswechsel** (Kontextwechsel) stattfindet, muss das Betriebssystem den Inhalt _aller_ dieser Register sichern (in den PCB oder auf den Stack). Wenn der Prozess später weiterrechnet, werden die alten Werte in die Register zurückgeladen, damit der Prozess exakt dort weitermachen kann, wo er unterbrochen wurde
#### Multicore
Um Leistung zu steigern, ohne die Taktfrequenz (Wärme!) zu erhöhen, nutzt man mehrere Kerne.
**Hyperthreading:** Ein Kern simuliert zwei logische Kerne.
**Multi-Core:** Echte physische Kerne auf einem Chip. Jeder Kern hat eigene Rechenwerke (ALU/FPU) und L1-Cache, teilt sich aber oft L2/L3-Cache.
### 4. Speicherhierarchie & Datenträger
**Cache (L1, L2, L3):** Puffer zwischen der sehr schnellen CPU und dem langsamen RAM. Ziel: Daten bereitstellen, bevor die CPU sie anfordert
• **RAM (Arbeitsspeicher):**
    ◦ _DRAM:_ Günstig, braucht Refresh-Zyklen (Kondensatoren entladen sich).
    ◦ _SRAM:_ Schnell, teuer, kein Refresh nötig (Flip-Flops)
• **Massenspeicher:**
    ◦ _HDD:_ Mechanisch, Fragmentierung ist ein Problem.
    ◦ _SSD:_ Flash-Speicher, keine beweglichen Teile, sehr schnell, verhält sich logisch wie eine Festplatte
### 5. Treiber
#### Das Grundproblem: Sprachbarrieren
Das Betriebssystem muss mit vielen unterschiedlichen internen und externen Geräten (Festplatte, Grafikkarte, Drucker, Netzwerkkarte) kommunizieren.
**Komplexität:** Jedes Gerät ist technisch anders aufgebaut und besitzt eine eigene, oft sehr komplizierte „Sprache“ (Protokolle, Befehlssätze),.
**Unmöglichkeit:** Das Betriebssystem selbst (der Kernel) kann unmöglich alle Sprachen aller existierenden (und zukünftigen) Geräte beherrschen,.
#### Die Hardware-Seite: Der Controller
Jedes Gerät besitzt einen **Geräte-Controller** (einen Hardware-Chip).
• Dieser Controller versteht die spezifische interne Sprache des Geräts und steuert die physischen Vorgänge (z.B. Schreibkopf bewegen, Pixel setzen).
• Der Controller ist der direkte Ansprechpartner für die Software,.
#### Die Software-Seite: Der Treiber
Der **Treiber** ist ein spezielles Programm (Teil des Betriebssystems), das als Übersetzer fungiert.
1. **Funktion:** Der Treiber kennt die Sprache des spezifischen Geräte-Controllers. Er übersetzt die allgemeinen Befehle des Betriebssystems (z.B. „Drucke Datei“) in die spezifischen Befehle für den Controller,.
2. **Kommunikation:** Er sorgt für den Datentransfer hin und her zwischen dem Hauptspeicher und dem Gerät,.
3. **Abstraktion:** Für manche standardisierten Schnittstellen (z.B. USB-Massenspeicher) gibt es generische Treiber, die für viele Geräte funktionieren. Meistens ist ein Treiber aber spezifisch für genau **ein** Gerät und genau **ein** Betriebssystem,.
#### Geschwindigkeit
Alle **E/A-Operationen** (Ein-/Ausgabe), die über Treiber laufen, sind im Vergleich zu reinen CPU-Register- oder RAM-Zugriffen extrem **langsam**. Daher versucht das BS oft, diese Wartezeiten durch Multitasking (Prozesswechsel) zu überbrücken.
### 6. Datenübertragung: DMA (Direct Memory Access)
**Problem:** Wenn die CPU jedes Byte einzeln von der Festplatte in den RAM kopieren müsste, wäre sie zu 100% ausgelastet ("zu schlau für dumme Arbeit")
**Lösung (DMA-Ablauf):**
1. Die **CPU** beauftragt den **DMA-Controller**: "Kopiere X Bytes von Adresse A nach B".
2. Die CPU widmet sich sofort anderen Prozessen (rechnet weiter).
3. Der **DMA-Controller** übernimmt den Bus und kopiert die Daten selbstständig.
4. Nach Abschluss sendet der DMA-Controller einen **Interrupt** an die CPU ("Fertig!").
5. Die CPU unterbricht ihre Arbeit kurz und bearbeitet das Ende des Transfers.
### 7. Kommunikation: Polling vs. Interrupts
#### 1. Polling (Aktives Warten)
Dies ist die ältere und einfachere, aber ineffiziente Methode.
**Das Prinzip:** Der Prozessor übernimmt die aktive Rolle. Er befindet sich in einer Schleife und fragt nacheinander jedes angeschlossene Gerät ab: _"Hast du Daten für mich? Hast du einen Auftrag?"_
**Der Ablauf:**
1. Die CPU stoppt ihre aktuelle Berechnung.
2. Sie fragt Gerät A: "Status?".
3. Sie fragt Gerät B: "Status?".
4. Wenn kein Gerät etwas will, nimmt die CPU die Berechnung wieder auf oder fängt die Runde von vorne an
**Die Nachteile (Warum wir es kaum noch nutzen):**
**Verschwendung:** Die CPU verbringt einen Großteil ihrer Zeit mit Fragen, auf die die Antwort meistens "Nein" lautet. Diese Zeit fehlt für echte Berechnungen
**Datenverlust:** Wenn die CPU gerade Gerät A bedient (Daten kopiert) und Gerät B in diesem Moment wichtige Daten empfängt (z.B. Netzwerkpakete), kann die CPU nicht reagieren. Da Gerät B oft keinen großen eigenen Speicher hat, gehen diese Daten verloren
#### 2. Interrupts (Unterbrechungen)
Dies ist der Standard in modernen Systemen. Hier melden sich die Geräte aktiv bei der CPU ("Event-Driven").
**Das Prinzip:** Die CPU kümmert sich nicht um die Geräte, sondern rechnet an ihrem Prozess. Wenn ein Gerät Aufmerksamkeit braucht, sendet es ein elektronisches Signal (Interrupt). Die CPU unterbricht ihre Arbeit _sofort_, erledigt den Job des Geräts und macht dann weiter, als wäre nichts gewesen
**Notwendige Hardware-Komponenten:** Damit das funktioniert, benötigt die CPU Hilfe:
**Interrupt-Register (IR):** Ein spezielles Register in der CPU, in dem Bits gesetzt werden, wenn eine Unterbrechung anliegt.
**Interrupt-Controller:** Ein Chip, der die Signale der vielen Geräte sammelt und geordnet an die CPU weiterleitet.
**Stack:** Ein Speicherbereich im RAM, um den Zustand der CPU (Kontext) kurzzeitig zu sichern.
**Interrupt-Vektoren:** Eine Tabelle im Speicher, die der CPU sagt: "Bei Fehler Nr. 5 springe zu Adresse X".
**ISR (Interrupt Service Routine):** Das kleine Programm (Treiber), das das Gerät tatsächlich bedient.
Der detaillierte Ablauf eines Interrupts am Beispiel einer Netzwerkkarte, die Daten empfängt:
1. **Ereignis:** Daten kommen an der Netzwerkkarte an. Da ihr Speicher klein ist, müssen sie sofort abgeholt werden.
2. **Signal:** Die Karte sendet ein Signal an den **Interrupt-Controller** (z.B. IRQ 5).
3. **Weiterleitung:** Der Interrupt-Controller setzt das entsprechende Bit (Nr. 5) im **Interrupt-Register (IR)** der CPU.
4. **Zyklus-Check:** Die CPU beendet ihren _aktuellen_ Befehl. Bevor sie den nächsten Befehl lädt, prüft sie automatisch das IR.
5. **Erkennung:** Die CPU sieht: "Bit 5 ist gesetzt!".
6. **Sicherung (Kontextwechsel):** Die CPU unterbricht das laufende Programm. Sie speichert alle wichtigen Registerinhalte und den Befehlszeiger auf den **Stack**.
7. **Lookup:** Die CPU schaut in der Vektortabelle nach Eintrag Nr. 5, um die Startadresse der passenden **ISR** zu finden.
8. **Ausführung:** Die CPU springt zur ISR. Die ISR kopiert die Daten von der Netzwerkkarte in den RAM.
9. **Restore:** Die ISR ist fertig. Die CPU lädt die alten Registerwerte vom Stack zurück.
10. **Weiter:** Das ursprüngliche Programm läuft an exakt der gleichen Stelle weiter.
#### Vergleich:
• Beim **Polling** geht die Initiative von der CPU aus (teuer, langsam).
• Beim **Interrupt** geht die Initiative vom Gerät aus (effizient, schnell).

View file

@ -0,0 +1,112 @@
# Zusammenfassung: IPC
## 1. Grundlagen und Motivation
Prozesse benötigen häufig einen Informationsaustausch (Beispiel: Ein E-Mail-Programm Mail User Agent sendet Daten an den Mail Transfer Agent). Da jeder Prozess grundsätzlich einen eigenen, isolierten Adressraum besitzt, ist eine direkte Kommunikation nicht trivial.
**Das Grundprinzip:**
- Für die Kommunikation ist gemeinsam genutzter Speicher (Shared Memory) zwingend erforderlich. Dies kann ein Bereich im Kernel-Adressraum sein oder eine Datei auf der Festplatte.
- Moderne Betriebssysteme erlauben es Prozessen, Teile ihres Adressraums explizit für andere freizugeben.
**Prozesse vs. Threads in der IPC:**
- Threads desselben Prozesses teilen sich bereits automatisch den Adressraum.
- Wenn zwei Prozesse einen gemeinsamen Speicherbereich nutzen, verhalten sie sich technisch fast identisch zu zwei Threads.
- Daher gilt der Leitsatz: **Interprozesskommunikation ist im Grunde immer Interthreadkommunikation.**
## 2. Das Problem: Race-Conditions (Wettlaufsituationen)
**Definition:** Eine Race-Condition entsteht, wenn mehrere Prozesse/Threads gleichzeitig auf gemeinsam beschreibbare Ressourcen zugreifen und das Endergebnis von der zufälligen zeitlichen Reihenfolge der Ausführung abhängt.
**Gefahren:**
- Race-Conditions führen zu semantischen Fehlern, die schwer zu finden sind (keine Syntaxfehler!).
- Der Code funktioniert meistens korrekt, stürzt aber sporadisch ab („Heisenbugs").
### Beispiel 1: Das Logdatei-Problem (Der Absturz)
Zwei Prozesse (A und B) wollen in dieselbe Logdatei schreiben:
1. Prozess A liest den Status: „Datei ist geschlossen". A setzt intern `is_open = false`.
2. **Kontextwechsel:** Die Zeitscheibe von A läuft ab, bevor A die Datei wirklich öffnen kann.
3. Prozess B kommt an die Reihe, liest den Status: „Datei ist geschlossen".
4. Prozess B öffnet die Datei, schreibt hinein und setzt den Status (physikalisch) auf „offen".
5. **Kontextwechsel:** B wird unterbrochen.
6. Prozess A läuft weiter. Da A intern gespeichert hat `is_open = false`, prüft es nicht erneut.
7. **Fehler:** A versucht, die (bereits offene) Datei erneut zu öffnen → Absturz oder Datenverlust.
### Beispiel 2: Lost Update (Datenbank)
Zwei Threads wollen einen Zähler (`counter = 0`) erhöhen. Code: `counter = counter + 1;`
Obwohl der Code logisch aussieht, passiert auf Maschinenebene Folgendes:
1. Thread A lädt Wert 0 in Register.
2. Thread B lädt Wert 0 in Register (bevor A schreibt).
3. A erhöht auf 1 und speichert.
4. B erhöht (seine 0) auf 1 und speichert. → Ergebnis ist 1 statt 2. Ein Update ging verloren.
## 3. Die Lösung: Der Kritische Bereich
**Definition:** Der Programmteil, in dem auf den gemeinsam genutzten Speicher zugegriffen wird, nennt sich **Kritischer Bereich (Critical Section)**.
### Die 4 zentralen Bedingungen für Synchronisation
Um Race-Conditions zu verhindern, muss das Betriebssystem folgende Regeln garantieren:
1. **Gegenseitiger Ausschluss (Mutual Exclusion):** Es dürfen sich niemals zwei Prozesse gleichzeitig im kritischen Bereich befinden.
2. **Keine Annahmen:** Die Lösung darf nicht von der Geschwindigkeit der Prozesse oder der Anzahl der CPUs abhängen.
3. **Keine Blockierung von außen:** Ein Prozess, der sich außerhalb seines kritischen Bereichs befindet, darf andere Prozesse nicht blockieren.
4. **Kein ewiges Warten (No Starvation):** Jeder Prozess muss irgendwann die Chance bekommen, in den kritischen Bereich einzutreten.
## 4. Mechanismus 1: Atomare Operationen
Das Grundproblem ist, dass Hochsprachen-Befehle (wie `i++`) nicht atomar (unteilbar) sind. Sie bestehen aus mehreren CPU-Befehlen (Load, Increment, Store), die unterbrochen werden können.
**Lösung auf Hardware-Ebene:** Prozessoren bieten spezielle Assembler-Instruktionen, die garantiert nicht unterbrochen werden können. Wären alle Befehle atomar, gäbe es keine Race-Conditions.
**Wichtige Assembler-Befehle:**
- **TSL (Test-and-Set-Lock):** Liest ein Byte aus dem Speicher in ein Register und schreibt im selben Taktzyklus einen neuen Wert (z.B. 1) an diese Stelle.
- **FAA (Fetch-and-Add):** Inkrementiert einen Wert im Speicher atomar.
- **CAS (Compare-and-Swap):** Vergleicht den Speicherinhalt mit einem Erwartungswert und tauscht ihn nur bei Übereinstimmung aus (Basis für lock-free Algorithmen).
- **XCHG (Exchange):** Tauscht die Inhalte zweier Register oder Speicheradressen atomar.
## 5. Mechanismus 2: Mutex (Mutual Exclusion)
**Konzept:** Ein Mutex ist eine Technik und Datenstruktur, die als "Schloss" dient.
- Nur der Thread, der den Mutex "besitzt" (lock), darf in den kritischen Bereich.
- Nur der Besitzer kann den Mutex wieder freigeben (unlock).
**Ablauf (Code-Schema):**
```c
pthread_mutex_lock(&m); // Versuche Schloss zu holen. Wenn belegt -> Warten.
/* KRITISCHER BEREICH (z.B. Schreiben in Datei) */
pthread_mutex_unlock(&m); // Schloss freigeben.
```
### Verhalten bei belegtem Mutex
Wenn Thread A den Mutex hat und Thread B ihn will, hat B drei Optionen:
1. **Passives Warten:** B gibt die CPU ab und wird vom OS "schlafen gelegt" (blocked), bis der Mutex frei ist.
2. **Aktives Warten (Spinlock):** B läuft in einer Schleife und prüft permanent („Ist frei? Ist frei?"). Sinnvoll nur bei sehr kurzen Wartezeiten auf Multi-Core-Systemen.
3. **Timeout:** B bricht den Versuch nach einer Zeit ab.
## 6. Mechanismus 3: Signale
**Eigenschaften:** Signale sind ein sehr altes Konzept (Unix) und stellen eine Software-Unterbrechung (Interrupt) dar. Sie können an Prozesse oder Threads gesendet werden.
**Funktionsweise:**
- Wenn ein Signal empfangen wird, unterbricht der Prozess seine Arbeit sofort.
- Entweder führt er eine ISR (Interrupt Service Routine) aus (benutzerdefiniert) oder die Standardaktion des Kernels (z.B. Prozess beenden).
- **Signalmaske:** Jeder Thread kann definieren, welche Signale er blockieren/ignorieren möchte.
**Wichtige POSIX-Funktionen:**
- `pthread_kill()`: Sendet Signal an einen Thread (nicht zwingend tödlich, dient als Benachrichtigung).
- `sigwait()`: Thread wartet passiv auf ein bestimmtes Signal.
## 7. Mechanismus 4: Semaphore (nach Dijkstra)
**Konzept:** Ein Semaphor ist mächtiger als ein Mutex. Er erlaubt den Zugriff einer vordefinierten Anzahl von Threads gleichzeitig.
### Datenstruktur
Ein Semaphor besteht aus zwei Elementen:
1. Einem Zähler (Integer).
2. Einer Warteschlange (Queue) für blockierte Threads.
### Die zwei Operationen
- **P() / wait():** Dekrementiert den Zähler.
- Ist der Zähler danach ≥ 0: Zugriff erlaubt.
- Ist der Zähler < 0 (bzw. war 0): Thread wird blockiert und in die Queue geschoben.
- **V() / signal():** Inkrementiert den Zähler.
- Wenn Threads in der Queue warten, wird einer geweckt.
### Unterschied zu Mutex
- Ein Mutex muss vom Besitzer freigegeben werden. Ein Semaphor kann von jedem Thread inkrementiert (V) werden (Asynchrone Signalisierung).
- Ein Semaphor mit Zähler = 1 (Binärer Semaphor) verhält sich wie ein Mutex.
### Beispiel: Bahnhofsüberwachung (Performance-Begrenzung)
**Szenario:** Es gibt viele Kameras, aber aus Performance-Gründen dürfen maximal 3 Such-Threads gleichzeitig Bilder analysieren.
- **Initialisierung:** `Semaphore s = new Semaphore(3);`
- **Thread startet:** `s.P()` (Zähler wird 2... dann 1... dann 0).
- Der 4. Thread muss warten (Zähler bleibt 0, Thread in Queue).
- **Thread fertig:** `s.V()` (Zähler wird 1, Wartender darf rein).
## 8. Mechanismus 5: Monitore
**Konzept:** Monitore sind ein Konstrukt auf höherer Abstraktionsebene (Sprachunterstützung). Ein Monitor ist ein gekapselter kritischer Bereich (z.B. eine Klasse oder Methode).
**Eigenschaften:**
- **Automatische Sicherheit:** Der Compiler garantiert, dass immer nur ein einziger Prozess/Thread gleichzeitig im Monitor aktiv ist.
- Programmierer müssen Lock/Unlock nicht manuell schreiben → weniger fehleranfällig.
**Implementierung in Java:**
- Schlüsselwort: `synchronized`.
- Kann auf Methoden (`synchronized void methode()`) oder Blöcke (`synchronized(this) { ... }`) angewendet werden.
### Bedingte Synchronisation (Warten im Monitor)
Oft muss ein Thread im Monitor warten, bis eine Bedingung erfüllt ist (z.B. Puffer nicht mehr leer). Dazu gibt es spezielle Methoden:
- `wait()`: Thread legt sich schlafen und gibt den Monitor frei, damit andere eintreten können.
- `notify()`: Weckt einen wartenden Thread (zufällig).
- `notifyAll()`: Weckt alle wartenden Threads (sicherer, um Deadlocks zu vermeiden).
## 9. Weitere Konzepte
### Das volatile Primitiv
- Kennzeichnet Variablen, die sich "außerhalb des Programmflusses" ändern können (z.B. durch Hardware oder andere Threads).
- **Effekt:** Der Compiler schaltet Optimierungen ab und erzwingt bei jedem Zugriff ein Lesen aus dem Hauptspeicher (statt aus dem schnellen CPU-Cache).
- **Achtung:** `volatile` garantiert Sichtbarkeit (Aktualität), aber keine Atomizität. Es ersetzt keinen Mutex bei komplexen Operationen.
### Parallele Programmiersprachen
Sprachen wie Occam, Ada oder Erlang besitzen eingebaute Kontrollstrukturen (z.B. `PAR` für parallele Ausführung oder Kanäle für Kommunikation), um Synchronisation direkt in der Syntax abzubilden, statt externe Bibliotheken zu nutzen.

View file

@ -0,0 +1,120 @@
# Zusammenfassung: Prozesse und Threads
## Der Prozess: Definition und Konzept
1. **Bessere Definition:** „Ein Prozess ist eine Instanz eines ausgeführten Programms, einschließlich der aktuellen Werte des Programmzählers, der Register und Variablen.“ [4].
2. **Umfassende Definition:** Ein Prozess ist der laufende Programmcode plus der Prozesskontext (alle Mittel und Parameter für die Ausführung) [5].
### Der Unterschied zwischen Programm und Prozess
Dieser Unterschied ist subtil, aber entscheidend. Ein Programm ist **passiv** (Code auf der Festplatte). Ein Prozess ist **aktiv** (Ressourcenzusammenfassung + Ausführung).
- Ein Prozess führt ein Programm aus.
- Viele Prozesse können dasselbe Programm ausführen. Jeder hat dabei seine eigene Instanz im eigenen Adressraum, völlig unabhängig von den anderen [6]
### Der Prozesskontext
Der Kontext umfasst alles, was die CPU zur Ausführung benötigt [5]:
- Registerwerte der CPU.
- Belegung des Caches (Befehle/Daten).
- Belegung des Hauptspeichers (Code/Daten).
- Benutzer- und Gruppenkennungen (IDs).
- Seitentabellen (Memory Management).
- Geöffnete Dateien.
- Prioritäten und Zustandsinformationen.
## Prozessverwaltung durch das Betriebssystem
### Process Control Block (PCB)
Das OS fasst alle Informationen eines Prozesses in einer Verwaltungsstruktur zusammen, dem PCB. Für jeden Prozess gibt es einen eigenen PCB. Die Gesamtheit aller PCBs bildet die Prozesstabelle [7].
- Je komplexer das OS, desto größer der PCB.
- Unter Linux ist die Struktur in `sched.h` definiert [8].
### Ressourcennutzung (Code-Sharing)
Da Prozesse Instanzen desselben Programms sein können, optimiert das OS den Speicher:
- **Codesegment (CS):** Wird nur einmal geladen und von allen Instanzen geteilt (spart Speicher und Zeit).
- **Datensegment (DS) & Stapel (SS):** Jeder Prozess erhält seine eigene Kopie.
- **Instruction Pointer (IP):** Jeder Prozess hat einen eigenen Zeiger, wo er sich im Code gerade befindet. So können Prozesse denselben Code an unterschiedlichen Stellen ausführen, ohne sich zu stören [8], [9].
### Hierarchie
Prozesse sind hierarchisch organisiert. Ein Elternprozess (_Parent_) erstellt einen Kindprozess (_Child_). Das Kind erbt Attribute vom Elternteil. Jeder Prozess kennt seine eigene ID (**PID**) und die des Elternprozesses (**PPID**) [10].
## Lebenszyklus eines Prozesses
Ein Prozess durchläuft verschiedene Phasen [11]:
1. Erstellung.
2. Ausführung auf dem Prozessor.
3. Anforderung von Ressourcen (Warten auf Zuweisung).
4. Warten auf Ergebnisse anderer Prozesse.
5. Erhalt einer Zeitscheibe (Quantum).
6. Warten auf die nächste Zeitscheibe (nach Entzug der CPU).
7. Beendigung.
### Wichtige Zustände (States)
Nicht zu verwechseln mit den Phasen, gibt es drei Hauptzustände in der Warteschlange [12]:
- **Bereit (Ready):** Wartet auf Zuteilung der CPU.
- **Rechnend (Running):** Führt Code aus.
- **Blockiert (Waiting):** Wartet auf ein Ereignis (z.B. I/O), CPU wurde entzogen.
### Kontextwechsel (Context Switch)
Der Wechsel von Prozess A zu Prozess B erfordert das Speichern des Zustands von A im PCB-A und das Laden von B aus PCB-B.
- Dies ist sehr zeitaufwändig.
- Hardware-Unterstützung (mehrere Registersätze) kann dies beschleunigen [13], [14].
### Prozessbeendigung
Ein Prozess kann auf drei Arten enden [15]:
1. **Normal:** Geplantes Ende (letzte Anweisung, `return`).
2. **Fehler:** Ungeplant (Nulldivision, Datei fehlt, Speicherfehler).
3. **Kill:** Befehl von außen (z.B. `kill -9 PID` unter Linux) [16].
**Probleme bei der Beendigung:**
- **Speicherlecks:** Wenn `malloc` genutzt wurde, aber kein `free`, bleibt Speicher belegt. Moderne Sprachen (Java, Go) nutzen Garbage Collection
- **Zombies:** Ein Prozess ist beendet, aber der Elternprozess hat den Status nicht abgefragt. Er bleibt als "Leiche" in der Tabelle
## Prozesserstellung: Linux vs. Windows
### Linux (`fork` & `exec`)
Das Verfahren ist zweistufig und sehr flexibel:
1. **`fork()`:** Erzeugt eine exakte Kopie des Elternprozesses.
- Der neue Prozess (Kind) beginnt an der gleichen Stelle (nach dem fork).
- **Unterscheidung durch Rückgabewert:**
- `0`: Ich bin das Kind.
- `PID > 0`: Ich bin der Elternprozess (Wert ist die PID des Kindes).
- `-1`: Fehler.
2. **`exec()` (optional):** Lädt ein neues Programm in den Speicher des Kindprozesses und überschreibt den alten Code.
### Windows
Nutzt den Systemaufruf `CreateProcess()`.
## Threads
**Definition:** Ein Thread ist ein sequenzieller Kontrollfluss innerhalb eines Prozesses. Ein Prozess kann mehrere Threads haben, die parallel ausgeführt werden. Threads dienen dazu, die Programmausführung zu beschleunigen und Aufgaben zu parallelisieren (z.B. Rechnen vs. E/A).
### Ressourcenteilung
Threads und Prozesse sind unterschiedliche Konzepte. Der Prozess dient der Ressourcengruppierung, der Thread ist die Einheit der Ausführung auf der CPU.
|**Gemeinsam genutzt (Shared)**|**Privat pro Thread (Private)**|
|---|---|
|Adressraum im Speicher|Program Counter (PC/IP)|
|Globale Variablen|Stack (Stapel)|
|Geöffnete Dateien|CPU-Register|
|Untergeordnete Prozesse|Zustand & Priorität|
|Benutzer-/Gruppen-ID|Signale (teils)|
|IPC-Mittel||
**Vorteile von Threads:**
- Erstellung ist 10- bis 100-mal schneller als bei Prozessen.
- Einfacher Zugriff auf gemeinsame Daten (kein komplexes IPC nötig).
- Echte Parallelität auf Multi-Core-Systemen [24].
## Thread-Modelle: User vs. Kernel
### A. User-Threads (Benutzer-Ebene)
Das Betriebssystem weiß nichts von diesen Threads. Sie werden von einer Bibliothek (Runtime System) im User-Space verwaltet.
- **Vorteile:**
- Keine Kernel-Aufrufe nötig (schnell).
- Verwaltung rein lokal im Prozessspeicher.
- Eigenes Scheduling möglich [28].
- **Nachteile:**
- **Blockierung:** Wenn ein Thread einen blockierenden Systemaufruf macht (z.B. Warten auf Tastatur), blockiert der gesamte Prozess (alle Threads stehen).
### B. Kernel-Threads (Betriebssystem-Ebene)
Das Betriebssystem kennt und verwaltet die Threads direkt.
- **Vorteile:**
- Wenn ein Thread blockiert, laufen andere weiter.
- Echte parallele Verteilung auf mehrere CPUs [30].
- **Nachteile:**
- Langsamer (Systemaufrufe nötig für Erstellung/Wechsel).
- Belegt mehr Speicher im Kernel [30], [31].
### C. Mapping (Die Verbindung)
Es muss eine Beziehung zwischen User- und Kernel-Threads geben [32], [33]:
- **Many-to-One:** Viele User-Threads auf einen Kernel-Thread (wie reines User-Threading).
- **One-to-One:** Jeder User-Thread hat einen Kernel-Thread (WinAPI, Linux Pthreads).
- **Many-to-Many:** Hybridansatz.
## Programmierung und Standards
POSIX Pthreads (IEEE 1003.1c):
Der Standard für Unix/Linux.
- **Bibliothek:** `pthread`
- **Funktionen:** `pthread_create`, `pthread_join` (warten auf Ende).
WinAPI Threads:
Der Standard für Windows.
- **Funktionen:** `CreateThread`, `WaitForSingleObject` (statt join), `CloseHandle`.
**Java & Go:**
- **Java:** Threads werden vom Runtime-System verwaltet (früher User-Threads, heute oft Mapping auf Kernel-Threads). Klasse `Thread` oder Interface `Runnable`. Starten mit `.start()` (ruft `.run()` auf) [33].
- **Go:** „Goroutinen“ (`go function()`). Sehr leichtgewichtig, vom Go-Runtime-System verwaltet [38], [39].

View file

@ -0,0 +1,121 @@
# Zusammenfassung: Scheduling
## 1. Grundlagen und Definitionen
**Was ist Scheduling?** Scheduling ist die Strategie und Methode, mit der das Betriebssystem die verfügbare Prozessorzeit (CPU-Zeit) auf die verschiedenen lauffähigen Prozesse oder Threads verteilt.
### Die drei Arten des Schedulings
1. **Kurzfristiges Scheduling (Short-Term / CPU-Scheduling):** Die Entscheidung, welcher Prozess als nächstes die CPU bekommt. (Dies ist der Fokus dieser Zusammenfassung)
2. **Mittelfristiges Scheduling:** Verwaltung des Arbeitsspeichers (Swapping, Prozess auslagern).
3. **Langfristiges Scheduling:** Entscheidung, welche Aufgaben (Jobs) überhaupt ins System zugelassen werden (Job-Queue).
### Wichtige Komponenten
- **Scheduler:** Die „Logik". Er entscheidet basierend auf einem Algorithmus, welcher Prozess als nächstes laufen darf.
- **Dispatcher:** Der „Mechaniker". Er führt den tatsächlichen Kontextwechsel durch. Er stoppt den alten Prozess, sichert den Status, lädt den neuen Status und übergibt die Kontrolle an die CPU.
- **Dispatch-Latenz:** Die Zeit, die der Dispatcher für das Umschalten braucht. Diese Zeit ist „Verlust" (Overhead) und sollte so gering wie möglich sein.
## 2. Prozess-Verhalten: Bursts
Prozesse arbeiten nicht linear. Sie wechseln ständig zwischen zwei Phasen:
1. **CPU-Burst:** Der Prozess rechnet aktiv (nutzt die CPU).
2. **E/A-Burst (I/O-Burst):** Der Prozess wartet auf Daten (Festplatte, Netzwerk, Tastatur) und nutzt die CPU nicht.
### Unterscheidung der Prozess-Typen
- **CPU-gebunden (CPU-bound):** Lange CPU-Bursts, seltenes Warten. (Beispiel: Videorendering, Simulationen)
- **E/A-gebunden (I/O-bound):** Kurze CPU-Bursts, häufiges Warten. (Beispiel: Texteditor, Webbrowser)
- **Ziel:** Ein guter Scheduler mischt diese Typen, um die Hardware optimal auszulasten.
## 3. Wann wird geschedult?
Der Scheduler muss in vier Situationen aktiv werden:
1. **Neuer Prozess:** Ein Programm wird gestartet.
2. **Prozessende:** Ein Prozess ist fertig.
3. **Blockierung:** Ein Prozess wartet auf E/A oder einen Semaphor/Mutex.
4. **Interrupt (nur bei Präemption):** Ein Hardware-Timer (Clock-Interrupt) unterbricht den laufenden Prozess.
## 4. Ziele des Schedulings
Die Ziele hängen stark von der Art des Systems ab. Es gibt oft Konflikte (z.B. Fairness vs. Effizienz).
### Allgemeine Ziele
- **Fairness:** Jeder Prozess erhält einen gerechten Anteil der CPU (Mindestzuteilung).
- **Effizienz:** Die CPU soll immer zu 100% beschäftigt sein (kein Leerlauf).
- **Balance:** Alle Systemteile (CPU, Disk, RAM) sollen ausgelastet sein.
- **Policy Enforcement:** Durchsetzung von Regeln (z.B. „Chef-Prozesse haben Vorrang").
### Spezifische Ziele nach Modus
**Batch-Systeme (Stapelverarbeitung):**
- Maximierung des Durchsatzes (Jobs pro Stunde).
- Minimierung der Durchlaufzeit (Zeit von Abgabe bis Fertigstellung).
**Interaktive Systeme (PC/Server):**
- Minimierung der Antwortzeit (Zeit bis zur ersten Reaktion auf eine Eingabe).
- Minimierung der Wartezeit in der "Bereit"-Schlange.
**Echtzeitsysteme:**
- Einhaltung von Deadlines (Fristen).
- Vorhersagbarkeit (kein Datenverlust durch Verzögerung).
## 5. Algorithmen-Konzepte: Präemptiv vs. Nicht-Präemptiv
### A. Nicht-Präemptiv (Kooperativ)
- Ein Prozess behält die CPU, bis er fertig ist, blockiert (I/O) oder sie freiwillig abgibt.
- **Vorteil:** Einfach, keine Timer-Hardware nötig.
- **Nachteil:** Ein Endlos-Schleifen-Prozess kann das ganze System einfrieren (Windows 3.1 Ära).
### B. Präemptiv (Verdrängend)
- Das OS kann einem Prozess die CPU gewaltsam entziehen.
- Benötigt Clock-Interrupts.
- Jeder Prozess erhält ein Zeitquantum (Zeitscheibe, typisch 10200 ms).
- **Faustregel:** Verhältnis Kontextwechsel zu Quantum sollte ca. 1:20 bis 1:50 betragen, um Overhead gering zu halten.
## 6. Die Scheduling-Algorithmen im Detail
### 6.1 FCFS (First Come First Serve)
- **Prinzip:** „Wer zuerst kommt, mahlt zuerst". Einfache Warteschlange (FIFO).
- **Typ:** Nicht-präemptiv.
- **Vorteil:** Sehr einfach zu implementieren.
- **Nachteil:** Konvoi-Effekt. Ein langer CPU-Prozess blockiert alle kurzen E/A-Prozesse. Führt zu schlechter Durchschnitts-Wartezeit.
### 6.2 SJF (Shortest Job First)
- **Prinzip:** Der Prozess mit dem kürzesten CPU-Burst wird als nächstes gewählt.
- **Typ:** Nicht-präemptiv.
- **Vorteil:** Garantiert die beste (minimale) durchschnittliche Wartezeit aller Verfahren.
- **Nachteil:** Die Laufzeit muss im Voraus bekannt sein (schwierig bei interaktiven Systemen). Gefahr von Starvation (Verhungern) langer Jobs, wenn immer neue kurze Jobs kommen.
### 6.3 SRTN (Shortest Remaining Time Next)
- **Prinzip:** Die präemptive Version von SJF. Wenn ein neuer Job kommt, dessen Laufzeit kürzer ist als der Rest des aktuellen Jobs, wird gewechselt.
- **Vorteil:** Sehr gut für kurze Jobs geeignet.
- **Nachteil:** Laufzeit muss bekannt sein; Overhead durch Überwachung der Restzeiten.
### 6.4 RR (Round Robin)
- **Prinzip:** Jeder Prozess bekommt die CPU für ein festes Zeitquantum (z.B. 20ms). Ist er nicht fertig, kommt er ans Ende der Schlange.
- **Typ:** Präemptiv.
- **Vorteil:** Der fairste Algorithmus. Keine Starvation. Gute Antwortzeit für Benutzer.
- **Nachteil:** Durchschnittliche Durchlaufzeit oft schlechter als SJF.
**Das Quantum-Problem:**
- **Zu groß:** RR verhält sich wie FCFS (schlechte Reaktion).
- **Zu klein:** Zu viele Kontextwechsel (CPU verbringt nur Zeit mit Umschalten, nicht mit Rechnen).
## 7. Prioritätsmechanismen
Priorität ist kein eigener Algorithmus, sondern ein Aufsatz auf andere (z.B. Priority-Queue statt FIFO).
### Hierarchie (Wer hat Vorrang?)
1. Kernel (Höchste Prio).
2. OS-Dienste / Treiber.
3. Interrupts.
4. GUI / Interaktive Apps.
5. Hintergrunddienste.
### Problem Starvation & Lösungen
Wenn Prozesse mit hoher Priorität die CPU monopolisieren, verhungern niedrige Prozesse.
- **Aging (Altern):** Die Priorität wartender Prozesse wird schrittweise erhöht.
- **Dynamische Anpassung:** Das OS beobachtet das Verhalten (z.B. Gauß-Methode oder Lotterie-Scheduling) und passt Prioritäten zur Laufzeit an.
## 8. Echtzeit-Modus (Real-Time)
Hier zählt nicht Geschwindigkeit, sondern Vorhersagbarkeit.
- **Harte Echtzeit:** Deadline muss gehalten werden (z.B. Airbag-Auslösung). Verspätung = Systemversagen.
- **Weiche Echtzeit:** Verspätung ist tolerierbar, aber Qualität sinkt (z.B. Video-Stream ruckelt).
- **Bedingung:** Das System ist nur planbar, wenn die Summe aller Prozess-Laufzeiten kleiner ist als die verfügbare CPU-Zeit.
## 9. Das große Rechenbeispiel (Klausur-relevant!)
Die Quelle vergleicht Algorithmen anhand von 5 Prozessen. Dies zeigt die Unterschiede in der Durchlaufzeit (Turnaround Time).
### Szenario
- **Prozesse:** A (Länge 12), B (6), C (7), D (2), E (9).
- **Prioritäten (0=hoch):** C(1), B(2), E(3), A(4), D(5). (Achtung: D hat niedrigste Prio!)
### A. FCFS (Reihenfolge A, B, C, D, E)
- A wartet 0, läuft 12 → Ende bei 12.
- B wartet auf A (12), läuft 6 → Ende bei 18.
- C endet bei 25.
- D endet bei 27.
- E endet bei 36.
- **Durchschnitt:** (12+18+25+27+36)/5 = **23,6**
### B. SJF (Sortiert nach Länge: D, B, C, E, A)
- D (2) läuft zuerst → Ende bei 2.
- B (6) startet bei 2 → Ende bei 8.
- C (7) startet bei 8 → Ende bei 15.
- E (9) startet bei 15 → Ende bei 24.
- A (12) startet bei 24 → Ende bei 36.
- **Durchschnitt:** (2+8+15+24+36)/5 = **17**
- **Fazit:** SJF ist der beste für den Durchsatz, aber unfair für A.
### C. Round Robin mit Priorität (Hier als Beispiel für "Worst Case")
- Im Beispiel führt dies zu vielen Wechseln und einer durchschnittlichen Zeit von 25,4.
- **Fazit:** RR ist der schlechteste für die Durchlaufzeit, aber der fairste Algorithmus.
## 10. Zusammenfassende Erkenntnisse für MC-Fragen
1. **Dispatcher vs. Scheduler:** Scheduler plant, Dispatcher schaltet.
2. **SJF:** Beste Performance, aber Gefahr von Starvation und schwer vorhersagbar.
3. **Round Robin:** Beste Fairness, Nutzung in interaktiven Systemen, abhängig vom Quantum.
4. **Batch vs. Interaktiv:** Batch will Durchsatz, Interaktiv will kurze Antwortzeiten.
5. **1:20 bis 1:50:** Das goldene Verhältnis von Overhead (Kontextwechsel) zu Nutzlast (Quantum).

View file

@ -0,0 +1,140 @@
# Zusammenfassung: Speicherverwaltung
## 1. Einführung: Die Direkte Speicherverwaltung
Die einfachste und historisch älteste Form der Speicherverwaltung ist die direkte Verwaltung.
- **Grundprinzip:** Alle Adressen, die im Programmcode stehen, entsprechen direkt den physikalischen Adressen im Hauptspeicher (RAM). Es gibt keine Übersetzungsschicht.
- **Beispiel:** Der Assembler-Befehl `mov AX, 42` bedeutet, dass der Prozessor direkt auf die physikalische Speicherzelle Nr. 42 zugreift und deren Inhalt in das Register AX lädt.
### Historische Speichertypen
Frühere Computer unterschieden strikt zwei Arten von Speicher:
1. **ROM (Read-Only-Memory):** Ein kleiner Speicher (ca. 64 KiB), der nicht überschrieben werden konnte. Er enthielt Boot-Funktionen, Treiber und Teile des Betriebssystems.
2. **RAM (Random-Access-Memory):** Der große Arbeitsspeicher für das Betriebssystem und die Benutzerprogramme.
### Organisation
Wenn nur ein einziges Benutzerprogramm und das Betriebssystem (OS) im Speicher sind, gab es drei Organisationsformen:
1. OS im RAM (unten), Benutzerprogramm darüber.
2. OS im ROM (oben), Benutzerprogramm im RAM.
3. Treiber im ROM, OS und Benutzerprogramm im RAM.
### Nachteile der direkten Verwaltung
Dieses Modell stößt schnell an Grenzen:
1. **Mangelnder Schutz:** Ein Programm kann versehentlich das Betriebssystem oder andere Programme beschädigen, da es Zugriff auf jedes physikalische Byte hat.
2. **Kein echtes Multitasking:** Es ist fast unmöglich, mehrere Programme gleichzeitig laufen zu lassen. Wenn zwei Programme hartkodierte Adressen nutzen (z.B. beide wollen an Adresse 1000 starten), können sie nicht gleichzeitig im Speicher liegen.
3. **Größenbeschränkung:** Das gesamte Programm muss vollständig in den physikalischen Speicher passen ("The whole program must be presented in memory").
## 2. Die erste Lösung: Adressräume & Swapping
Um die Probleme der direkten Verwaltung zu lösen, wurden Adressräume eingeführt. Ein Adressraum ist die Menge aller Adressen, die ein Prozess verwenden darf. Jeder Prozess erhält seinen eigenen, isolierten Raum.
### Hardware-Unterstützung (Basis & Limit)
Der Prozessor nutzt zwei spezielle Register zur Verwaltung:
1. **Basisregister:** Enthält die physikalische Startadresse des Programms.
2. **Grenzwertregister (Limit):** Enthält die Gesamtlänge des Programms.
- **Berechnung:** Die effektive physikalische Adresse = Programmadresse + Basisregister.
- **Schutz:** Die Hardware prüft bei jedem Zugriff: Effektive Adresse ≤ Basis + Limit. Ist dies nicht der Fall, wird der Zugriff verweigert (Schutzverletzung).
### Das Konzept des Swapping (Auslagerung)
Da der Arbeitsspeicher selten groß genug ist, um alle Prozesse gleichzeitig vollständig zu halten, nutzt das OS "Swapping".
- **Vorgang:** Wenn der Platz knapp wird, wird ein inaktiver Prozess komplett auf die Festplatte geschrieben (ausgelagert) und ein anderer Prozess komplett in den Speicher geladen.
- **Problem der Fragmentierung:** Durch das ständige Ein- und Auslagern entstehen ungenutzte Lücken ("Löcher") zwischen den Prozessen. Der Speicher zerstückelt.
- **Lösung:** Das OS muss den Speicher defragmentieren (komprimieren), was jedoch sehr rechenaufwändig ist.
### Speicherzuweisungs-Algorithmen (Allocation Algorithms)
Wenn ein neuer Prozess geladen werden soll, muss das OS eine passende Lücke im RAM finden. Hierfür gibt es fünf klassische Strategien:
1. **First Fit:** Wählt die erste Lücke, die groß genug ist. Schnell, aber fragmentiert den Speicher vorne.
2. **Next Fit:** Beginnt die Suche dort, wo die letzte Zuweisung endete.
3. **Best Fit:** Sucht die kleinste Lücke, die gerade so ausreicht. Nachteil: Hinterlässt winzige, nutzlose Rest-Lücken.
4. **Worst Fit:** Wählt die größte verfügbare Lücke. Idee: Der Rest ist groß genug für weitere Prozesse.
5. **Quick Fit:** Hält separate Listen für häufig benötigte Lückengrößen bereit.
## 3. Virtuelle Speicherverwaltung (Paging)
Das ist der Standard in allen modernen Systemen (Windows, Linux, Android, macOS). Es entkoppelt die Sicht des Programms von der physikalischen Realität.
### Kernkonzepte
- **Virtueller Speicher:** Das Programm "sieht" einen perfekten, linearen Speicher, der in Pages (Seiten) unterteilt ist.
- **Physischer Speicher:** Der RAM ist in Frames (Seitenrahmen) unterteilt.
- **Mapping:** Es gilt immer: Größe Frame = Größe Page (Standard ist oft 4 KiB).
- **Vorteil:** Ein Programm kann größer sein als der physikalische Speicher. Die Seiten müssen nicht zusammenhängend im RAM liegen.
### MMU (Memory Management Unit)
Die MMU ist ein Hardware-Baustein direkt auf dem Prozessor-Chip.
- **Aufgabe:** Sie übersetzt bei jedem Speicherzugriff die virtuelle Adresse in eine physikalische Adresse.
- **Richtung:** Immer Virtuell → Physikalisch (niemals umgekehrt!).
### Berechnung der optimalen Seitengröße
Die Wahl der Seitengröße ist ein Kompromiss.
- **Kleine Seiten:** Weniger Verschnitt (interne Fragmentierung), aber riesige Verwaltungstabellen.
- **Große Seiten:** Kleine Tabellen, aber viel ungenutzter Platz am Ende der letzten Seite.
- **Formel:** p = √(2 · s · e)
- p: Seitengröße
- s: Durchschnittliche Prozessgröße
- e: Größe eines Seitentabellen-Eintrags
- Beispiel: Bei 1 MiB Programmgröße und 8 Byte Eintrag ergibt sich mathematisch eine optimale Größe von 4 KiB.
## 4. Datenstrukturen: Seitentabellen & TLB
### Die Seitentabelle (Page Table)
Jeder Prozess besitzt eine eigene Seitentabelle im RAM. Sie dient der MMU als Nachschlagewerk. Ein Eintrag in dieser Tabelle (typisch 32 Bit / 4 Byte) enthält komplexe Statusinformationen:
1. **Rahmennummer:** Die eigentliche physikalische Adresse im RAM (wo liegt die Seite?).
2. **Present/Absent Bit (P):**
- 1: Seite ist im RAM (Zugriff okay).
- 0: Seite ist nicht im RAM (löst Seitenfehler / Page Fault aus).
3. **Modified Bit (M) / Dirty Bit:**
- 1: Die Seite wurde verändert (geschrieben). Sie muss beim Entfernen auf die Festplatte zurückgesichert werden.
- 0: Seite ist sauber (identisch mit der Festplatte), kann einfach überschrieben werden.
4. **Referenced Bit (R):**
- 1: Seite wurde kürzlich gelesen oder beschrieben. Wichtig für Ersetzungs-Algorithmen. Das OS setzt dieses Bit periodisch auf 0 zurück.
5. **Schutz-Bits (RWX):** Definieren Rechte (Read, Write, Execute).
### Das Problem der Größe
Da jeder Prozess eine Tabelle braucht, kann dies viel Speicher kosten. Bei 32-Bit oder 64-Bit Systemen können Tabellen mehrere Megabyte groß werden (z.B. 4 MiB).
- **Lösung:** Mehrstufige Seitentabellen (Paged Page Tables).
### TLB (Translation Lookaside Buffer)
Da ein Zugriff auf die Seitentabelle im RAM langsam ist (Verdopplung der Zugriffszeit: 1x Tabelle lesen, 1x Daten lesen), nutzt die MMU einen Hardware-Cache namens TLB.
- Der TLB speichert die häufigsten Übersetzungen.
- Die MMU prüft zuerst den TLB. Nur bei einem "Miss" greift sie auf die langsame Tabelle im RAM zu.
## 5. Seitenersetzungs-Algorithmen (Page Replacement)
Wenn der physikalische Speicher voll ist und eine neue Seite geladen werden muss (Demand Paging), muss eine alte Seite weichen ("Opfer"). Welcher Algorithmus trifft diese Entscheidung?
### A. NRU (Not Recently Used)
Klassifiziert Seiten anhand der R- und M-Bits in 4 Klassen:
- **Klasse 0:** Nicht referenziert, nicht modifiziert. (Bestes Opfer).
- **Klasse 1:** Nicht referenziert, modifiziert.
- **Klasse 2:** Referenziert, nicht modifiziert.
- **Klasse 3:** Referenziert, modifiziert. (Schlechtes Opfer, wird oft gebraucht).
**Strategie:** Löscht zufällig eine Seite aus der niedrigsten vorhandenen Klasse. Einfach, aber mäßig effizient.
### B. FIFO (First-In-First-Out)
- **Strategie:** Führt eine Liste aller Seiten. Die älteste (zuerst geladene) Seite fliegt raus.
- **Nachteil:** Die älteste Seite kann eine wichtige Kernel-Bibliothek sein, die ständig benötigt wird. FIFO ist daher in Reinform ineffizient.
### C. Second Chance (SC)
Eine Verbesserung von FIFO. Prüft das R-Bit der ältesten Seite:
- **R=0:** Seite ist alt und unbenutzt → Raus.
- **R=1:** Seite ist alt, aber aktiv → R-Bit löschen, Seite ans Ende der Liste verschieben (wie neu geladen). Sie erhält eine "zweite Chance".
### D. Clock (Uhr-Algorithmus)
- Eine effizientere Implementierung von Second Chance mittels einer zirkulären Liste (wie ein Zifferblatt).
- Ein Zeiger dreht sich im Kreis. Trifft er auf R=1, setzt er es auf 0 und geht weiter. Trifft er auf R=0, wird die Seite ersetzt.
### E. LRU (Least Recently Used)
- **Idee:** Die Vergangenheit sagt die Zukunft voraus. Seiten, die lange nicht genutzt wurden, werden wohl auch bald nicht gebraucht.
- **Implementierung:** Theoretisch bräuchte man einen Zeitstempel bei jedem Zugriff (zu teuer).
- **Praxis:** Hardware-Zähler in der Seitentabelle oder Matrix-Methoden. Gilt als einer der besten Algorithmen.
### F. Working Set (WS)
- Definiert eine "Arbeitsmenge" an Seiten, die ein Prozess in einem Zeitfenster τ (z.B. 100ms) benötigt hat.
- **Strategie:** Entferne nur Seiten, die nicht zum aktuellen Working Set gehören. Verhindert "Thrashing" (das System ist nur noch mit Auslagern beschäftigt).
## 6. Der Ablauf eines Seitenfehlers (Page Fault)
Was passiert im Detail, wenn ein Prozess auf eine Adresse zugreift, deren Present-Bit 0 ist? Dies ist ein komplexer Vorgang in 11 Schritten:
1. **Trap:** Die Hardware bemerkt den Fehler. Ein Interrupt wird ausgelöst, der Programmzähler (PC) wird im Stack gesichert. Der Modus wechselt zu Kernel-Mode.
2. **Sichern:** Alle flüchtigen Informationen (Register) werden gespeichert.
3. **Identifikation:** Das OS ermittelt, welche virtuelle Adresse den Fehler verursacht hat (steht oft in einem Spezialregister der CPU).
4. **Validierung:** Das OS prüft: Ist die Adresse überhaupt gültig? Hat der Prozess Rechte dafür? Falls nein → Prozess-Abbruch (Segmentation Fault).
5. **Rahmensuche:** Das OS sucht einen freien physikalischen Rahmen. Falls keiner frei ist, muss der Seitenersetzungsalgorithmus (siehe Punkt 5) ausgeführt werden, um Platz zu schaffen.
6. **Auslagern (Eviction):** Wenn die "Opfer-Seite" modifiziert war (M=1), muss sie erst auf die Festplatte geschrieben werden.
7. **Kontextwechsel:** Da Festplattenzugriffe langsam sind, wird der aktuelle Prozess blockiert und ein anderer Prozess darf solange rechnen (CPU-Nutzung optimieren).
8. **Laden:** Die eigentlich angeforderte Seite wird nun von der Festplatte in den freien Rahmen geladen.
9. **Update:** Die Seitentabelle wird aktualisiert: Rahmennummer eintragen, Present-Bit auf 1 setzen.
10. **Wiederherstellung (Restore):** Die gesicherten Register des Prozesses werden wiederhergestellt. Der Programmzähler wird auf den Befehl zurückgesetzt, der den Fehler verursachte.
11. **Fortsetzung:** Der Befehl wird erneut ausgeführt diesmal erfolgreich, da die Seite nun im RAM ist.
## 7. Segmente & Speicherschutz
Ein moderner Prozess-Adressraum ist nicht homogen, sondern in logische Segmente unterteilt, die unterschiedliche Rechte (Schutz-Bits) haben:
1. **Code-Segment (Text):** Enthält die Maschinenbefehle.
- Rechte: Nur Lesen und Ausführen (r-x). Schreiben ist verboten (verhindert selbst-modifizierenden Code).
2. **Daten-Segment:** Enthält globale Variablen.
- Rechte: Lesen und Schreiben (rw-). Ausführen verboten (Schutz vor Buffer-Overflow-Exploits).
3. **Stack-Segment:** Für lokale Variablen und Funktionsaufrufe. (rw-).
4. **Heap-Segment:** Für dynamisch angeforderten Speicher (malloc / new). (rw-).
### Segmentation Fault
Ein "Segfault" tritt auf, wenn ein Programm versucht, auf eine Adresse zuzugreifen, für die es keine Rechte hat (z.B. Schreiben in Code-Segment) oder die nicht existiert (z.B. Dereferenzierung eines Null-Zeigers).
## 8. Vergleich: Swapping vs. Paging
|Merkmal|Swapping (Veraltet)|Paging (Modern)|
|---|---|---|
|**Einheit**|Ganzer Prozess wird verschoben.|Einzelne Seiten (Teile) werden verschoben.|
|**Speicherart**|Nur bei direkter Speicherverwaltung nötig.|Nur bei virtueller Speicherverwaltung.|
|**Effizienz**|Gering (große Datenmengen, Fragmentierung).|Hoch (feingranular, nur benötigte Teile).|
|**Hardware**|Benötigt Basis-/Limit-Register.|Benötigt MMU und Seitentabellen.|
### Demand Paging
Moderne Systeme laden Seiten nicht im Voraus ("Prefetching"), sondern strikt nach Bedarf ("Demand"). Eine Seite wird erst geladen, wenn ein Page Fault auftritt. Das spart Speicher und I/O-Bandbreite.