21.07.2013 Aufrufe

Systemnahe Programmierung

Systemnahe Programmierung

Systemnahe Programmierung

MEHR ANZEIGEN
WENIGER ANZEIGEN

Erfolgreiche ePaper selbst erstellen

Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.

<strong>Systemnahe</strong> <strong>Programmierung</strong><br />

Johann Schlichter<br />

Institut für Informatik<br />

TU München, Munich, Germany<br />

Oktober 2003<br />

Vorlesungsunterlagen<br />

(Student Script 1 )<br />

1 Script generated by Targeteam; Not for general Distribution


Inhaltsverzeichnis<br />

1 Übersicht 2<br />

1.1 Ziel der Vorlesung . . . . . . . . . . . . . . . . . . . . . . . . . . 2<br />

1.2 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3<br />

1.2.1 Anforderungen an Rechensysteme . . . . . . . . . . . . . 3<br />

1.2.2 Struktur eines Rechensystems . . . . . . . . . . . . . . . 6<br />

1.3 Themen der Vorlesung . . . . . . . . . . . . . . . . . . . . . . . 8<br />

1.3.1 Laufzeitmodell . . . . . . . . . . . . . . . . . . . . . . . 8<br />

1.3.2 Inhaltsübersicht . . . . . . . . . . . . . . . . . . . . . . . 9<br />

1.4 Literaturübersicht . . . . . . . . . . . . . . . . . . . . . . . . . . 10<br />

1.4.1 Begleitend zur Vorlesung . . . . . . . . . . . . . . . . . . 10<br />

1.4.2 Begleitend zur Übung . . . . . . . . . . . . . . . . . . . 10<br />

1.4.3 Weiterführende Literatur . . . . . . . . . . . . . . . . . . 10<br />

2 Rechner und hardwarenahe Programme 12<br />

2.1 Fragestellungen . . . . . . . . . . . . . . . . . . . . . . . . . . . 12<br />

2.2 von Neumann Rechner . . . . . . . . . . . . . . . . . . . . . . . 12<br />

2.3 Architektur sequentieller Rechner . . . . . . . . . . . . . . . . . 14<br />

2.3.1 Blockdiagramm für eine Architektur . . . . . . . . . . . . 14<br />

2.3.2 Befehlsgrundzyklus . . . . . . . . . . . . . . . . . . . . . 17<br />

2.3.3 E/A Architekturvarianten . . . . . . . . . . . . . . . . . . 18<br />

2.3.4 Architektur der MI . . . . . . . . . . . . . . . . . . . . . 19<br />

2.4 Befehlsvorrat eines Rechners . . . . . . . . . . . . . . . . . . . . 20<br />

2.4.1 Charakterisierung der Befehle . . . . . . . . . . . . . . . 20<br />

2.4.2 Aufbau Maschinenbefehle . . . . . . . . . . . . . . . . . 22<br />

i


Schlichter, TU München INHALTSVERZEICHNIS<br />

2.4.3 Befehle der MI . . . . . . . . . . . . . . . . . . . . . . . 30<br />

2.5 Hardwarenahe Programme . . . . . . . . . . . . . . . . . . . . . 34<br />

2.5.1 Definitionen . . . . . . . . . . . . . . . . . . . . . . . . 34<br />

2.5.2 Programmaufbereitung . . . . . . . . . . . . . . . . . . . 35<br />

2.5.3 MI Assemblerprogramm . . . . . . . . . . . . . . . . . . 36<br />

2.5.4 Assembler Grundfunktionen . . . . . . . . . . . . . . . . 38<br />

2.5.5 Assemblerläufe . . . . . . . . . . . . . . . . . . . . . . . 40<br />

2.5.6 Binder und Lader . . . . . . . . . . . . . . . . . . . . . . 44<br />

2.6 Hardwarenahe Datenstrukturen . . . . . . . . . . . . . . . . . . . 49<br />

2.6.1 Felder . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<br />

2.6.2 Programme im Arbeitsspeicher . . . . . . . . . . . . . . . 53<br />

3 Parallele Systeme 59<br />

3.1 Fragestellungen . . . . . . . . . . . . . . . . . . . . . . . . . . . 59<br />

3.2 Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60<br />

3.2.1 Begriffsdefinitionen . . . . . . . . . . . . . . . . . . . . 61<br />

3.2.2 Beschreibungskonzepte . . . . . . . . . . . . . . . . . . . 62<br />

3.3 Modellierung paralleler Systeme . . . . . . . . . . . . . . . . . . 63<br />

3.3.1 Modellierungsziele . . . . . . . . . . . . . . . . . . . . . 64<br />

3.3.2 Verhaltensbeschreibung . . . . . . . . . . . . . . . . . . 65<br />

3.3.3 Ereignisse und Aktionsstrukturen . . . . . . . . . . . . . 66<br />

3.3.4 Aktionen als Zustandsübergänge . . . . . . . . . . . . . . 72<br />

3.3.5 Petri-Netze . . . . . . . . . . . . . . . . . . . . . . . . . 77<br />

3.4 Thread-Konzept . . . . . . . . . . . . . . . . . . . . . . . . . . . 89<br />

3.4.1 Charakterisierung von Threads . . . . . . . . . . . . . . . 90<br />

3.4.2 Threads in Java . . . . . . . . . . . . . . . . . . . . . . . 93<br />

3.5 Synchronisation . . . . . . . . . . . . . . . . . . . . . . . . . . . 96<br />

3.5.1 Beispiele . . . . . . . . . . . . . . . . . . . . . . . . . . 96<br />

3.5.2 Definition: Wechselseitiger Ausschluss . . . . . . . . . . 98<br />

3.5.3 Modellierung . . . . . . . . . . . . . . . . . . . . . . . . 99<br />

3.5.4 Synchronisierungskonzepte . . . . . . . . . . . . . . . . 100<br />

3.5.5 Semaphore . . . . . . . . . . . . . . . . . . . . . . . . . 105<br />

3.5.6 Synchronisierung von Java Threads . . . . . . . . . . . . 111<br />

ii


Schlichter, TU München INHALTSVERZEICHNIS<br />

3.6 Verklemmungen . . . . . . . . . . . . . . . . . . . . . . . . . . . 112<br />

3.6.1 Allgemeines . . . . . . . . . . . . . . . . . . . . . . . . 113<br />

3.6.2 Belegungs-Anforderungsgraph . . . . . . . . . . . . . . . 113<br />

3.6.3 Verklemmungs-Erkennung . . . . . . . . . . . . . . . . . 114<br />

3.6.4 Verklemmungs-Vermeidung . . . . . . . . . . . . . . . . 114<br />

3.6.5 Verklemmungs-Verhinderung . . . . . . . . . . . . . . . 115<br />

4 Prozess- und Prozessorverwaltung 118<br />

4.1 Fragestellungen . . . . . . . . . . . . . . . . . . . . . . . . . . . 118<br />

4.2 Betriebssystem - Überblick . . . . . . . . . . . . . . . . . . . . . 119<br />

4.2.1 BS-Hauptaufgaben . . . . . . . . . . . . . . . . . . . . . 119<br />

4.2.2 Systemprogrammierung . . . . . . . . . . . . . . . . . . 120<br />

4.2.3 Betriebssystem-Architektur . . . . . . . . . . . . . . . . 121<br />

4.2.4 Betriebsarten . . . . . . . . . . . . . . . . . . . . . . . . 126<br />

4.3 Prozessverwaltung . . . . . . . . . . . . . . . . . . . . . . . . . 127<br />

4.3.1 Prozesskonzept . . . . . . . . . . . . . . . . . . . . . . . 127<br />

4.3.2 Dispatcher . . . . . . . . . . . . . . . . . . . . . . . . . 131<br />

4.3.3 Arbeitsmodi . . . . . . . . . . . . . . . . . . . . . . . . 132<br />

4.3.4 Systemaufrufe . . . . . . . . . . . . . . . . . . . . . . . 133<br />

4.3.5 Realisierung von Threads . . . . . . . . . . . . . . . . . 137<br />

4.4 Prozessorverwaltung . . . . . . . . . . . . . . . . . . . . . . . . 140<br />

4.4.1 Kriterien . . . . . . . . . . . . . . . . . . . . . . . . . . 140<br />

4.4.2 Scheduling-Strategien . . . . . . . . . . . . . . . . . . . 141<br />

4.4.3 Beispiel Unix Scheduling . . . . . . . . . . . . . . . . . 144<br />

4.4.4 Thread Scheduling . . . . . . . . . . . . . . . . . . . . . 145<br />

4.4.5 Mehrschichtiges Scheduling . . . . . . . . . . . . . . . . 147<br />

4.4.6 Echtzeit Scheduling . . . . . . . . . . . . . . . . . . . . 148<br />

4.5 Unterbrechungskonzept . . . . . . . . . . . . . . . . . . . . . . . 150<br />

4.5.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . 150<br />

4.5.2 Unterbrechungsarten . . . . . . . . . . . . . . . . . . . . 151<br />

4.5.3 Behandlung externer Unterbrechungen . . . . . . . . . . 153<br />

4.5.4 Konflikte . . . . . . . . . . . . . . . . . . . . . . . . . . 154<br />

iii


Schlichter, TU München INHALTSVERZEICHNIS<br />

5 Speicherverwaltung 158<br />

5.1 Fragestellungen . . . . . . . . . . . . . . . . . . . . . . . . . . . 158<br />

5.2 Einführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158<br />

5.2.1 Adressräume . . . . . . . . . . . . . . . . . . . . . . . . 159<br />

5.2.2 Organisation von Adressräumen . . . . . . . . . . . . . . 160<br />

5.2.3 Fragmentierung . . . . . . . . . . . . . . . . . . . . . . . 162<br />

5.2.4 Forderungen an Adressraumrealisierung . . . . . . . . . . 164<br />

5.3 Speicherabbildungen . . . . . . . . . . . . . . . . . . . . . . . . 165<br />

5.3.1 Direkte Adressierung . . . . . . . . . . . . . . . . . . . . 165<br />

5.3.2 Basisadressierung . . . . . . . . . . . . . . . . . . . . . . 167<br />

5.4 Virtueller Speicher . . . . . . . . . . . . . . . . . . . . . . . . . 168<br />

5.4.1 Seitenadressierung . . . . . . . . . . . . . . . . . . . . . 168<br />

5.4.2 Segment-Seitenadressierung . . . . . . . . . . . . . . . . 179<br />

5.4.3 Speicherverwaltung der MI . . . . . . . . . . . . . . . . . 180<br />

6 Dateisysteme 182<br />

6.1 Fragestellungen . . . . . . . . . . . . . . . . . . . . . . . . . . . 182<br />

6.2 Charakteristika von Dateisystemen . . . . . . . . . . . . . . . . . 183<br />

6.3 Dateien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184<br />

6.4 Memory-Mapped Dateien . . . . . . . . . . . . . . . . . . . . . . 187<br />

6.5 Verzeichnisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187<br />

6.6 Schichtenmodell . . . . . . . . . . . . . . . . . . . . . . . . . . 188<br />

6.6.1 Datenträgerorganisation . . . . . . . . . . . . . . . . . . 188<br />

6.6.2 Blockorientiertes Dateisystem . . . . . . . . . . . . . . . 189<br />

6.6.3 Dateiverwaltung . . . . . . . . . . . . . . . . . . . . . . 189<br />

6.7 Einbettung der E/A . . . . . . . . . . . . . . . . . . . . . . . . . 190<br />

7 Prozesskommunikation 191<br />

7.1 Fragestellungen . . . . . . . . . . . . . . . . . . . . . . . . . . . 191<br />

7.2 Einführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192<br />

7.2.1 Kommunikationsarten . . . . . . . . . . . . . . . . . . . 192<br />

7.2.2 Verteilte Systeme . . . . . . . . . . . . . . . . . . . . . . 196<br />

7.3 Nachrichtenbasierte Kommunikation . . . . . . . . . . . . . . . . 198<br />

iv


Schlichter, TU München INHALTSVERZEICHNIS<br />

7.3.1 Elementare Kommunikationsmodelle . . . . . . . . . . . 198<br />

7.3.2 Erzeuger-Verbraucher Problem . . . . . . . . . . . . . . . 204<br />

7.3.3 Modellierung durch ein Petrinetz . . . . . . . . . . . . . . 204<br />

7.3.4 Ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205<br />

7.3.5 Kanäle . . . . . . . . . . . . . . . . . . . . . . . . . . . 207<br />

7.3.6 Ströme . . . . . . . . . . . . . . . . . . . . . . . . . . . 207<br />

7.4 Client-Server-Modell . . . . . . . . . . . . . . . . . . . . . . . . 208<br />

7.5 Netzwerkprogrammierung . . . . . . . . . . . . . . . . . . . . . 210<br />

7.5.1 Einführung . . . . . . . . . . . . . . . . . . . . . . . . . 211<br />

7.5.2 Server Protokoll . . . . . . . . . . . . . . . . . . . . . . 212<br />

7.5.3 Client Protokoll . . . . . . . . . . . . . . . . . . . . . . . 213<br />

7.5.4 Bidirektionale Stromverbindung . . . . . . . . . . . . . . 214<br />

7.5.5 Java Socket Class . . . . . . . . . . . . . . . . . . . . . . 214<br />

7.6 Remote Procedure Call . . . . . . . . . . . . . . . . . . . . . . . 216<br />

8 Sicherheit in Rechensystemen 223<br />

8.1 Fragestellungen . . . . . . . . . . . . . . . . . . . . . . . . . . . 223<br />

8.2 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223<br />

8.3 Schutzmechanismen . . . . . . . . . . . . . . . . . . . . . . . . 228<br />

8.3.1 Anforderungen . . . . . . . . . . . . . . . . . . . . . . . 228<br />

8.3.2 Ebenen des Zugriffschutzes . . . . . . . . . . . . . . . . 229<br />

8.3.3 Schutzmatrix . . . . . . . . . . . . . . . . . . . . . . . . 229<br />

8.4 Sicherheit in verteilten Systemen . . . . . . . . . . . . . . . . . . 234<br />

8.4.1 Unsicherheitsfaktoren in verteilten Systemen . . . . . . . 234<br />

8.4.2 Sicherheitsanforderungen . . . . . . . . . . . . . . . . . 235<br />

8.4.3 Kryptographie . . . . . . . . . . . . . . . . . . . . . . . 236<br />

8.4.4 Authentifizierungsdienst Kerberos . . . . . . . . . . . . . 240<br />

8.4.5 Mobiler Code . . . . . . . . . . . . . . . . . . . . . . . . 245<br />

9 Zusammenfassung 248<br />

v


Schlichter, TU München INHALTSVERZEICHNIS<br />

¯ Prof. J. Schlichter<br />

– Lehrstuhl für Angewandte Informatik / Kooperative Systeme, Fakultät für<br />

Informatik, TU München<br />

– Boltzmannstr. 3, 85748 Garching<br />

Email: schlichter@in.tum.de (URL: mailto:schlichter@in.tum.de)<br />

Tel.: 089-289 18654<br />

URL: http://www11.informatik.tu-muenchen.de/<br />

1


Kapitel 1<br />

Übersicht<br />

1.1 Ziel der Vorlesung<br />

Diese Vorlesung beschäftigt sich mit den technischen Aspekten von Rechensystemen<br />

und der Informationsverarbeitung, insbesondere der systemnahen <strong>Programmierung</strong>.<br />

Dabei werden sowohl nicht verteilte als auch verteilte Systeme betrachtet.<br />

¯ Der erste Teil der Vorlesung behandelt hardwarenahe Programm- und Datenstrukturen.<br />

Deshalb wird zunächst die Modellmaschine MI (basierend auf einer<br />

VAX Architektur von vormals Digital Equipment) vorgestellt. Diese Maschine<br />

dient als Basis zur Diskussion des Aufbaus von typischen Maschinenund<br />

Assemblerbefehlen. Anhand dieser Modellmaschine wird die Entwicklung<br />

von Programmen unter Berücksichtigung der jeweiligen Komponenten einer<br />

Hardwarekonfiguration aufgezeigt. Die einfachen Programme, die zunächst<br />

entwickelt werden, werden dann zu den Programm- und Datenstrukturen verallgemeinert,<br />

die heute für hardwarenahe Systemebenen verwendet werden.<br />

¯ Im nächsten Teil der Vorlesung erfolgt eine wichtige Verallgemeinerung,<br />

nämlich der Übergang von sequentiellen zu parallelen Systemen und die<br />

Entwicklung von parallelen Systemen. Zu den Themen, die behandelt werden,<br />

gehören die Grundlagenprobleme paralleler Systeme und die Verfahren, mit<br />

denen diese gelöst werden können: Modellierung des Systemverhaltens,<br />

Synchronisation, Verklemmungen.<br />

¯ Im Anschluss daran werden Konzepte und Verfahren sowie der Aufbau von<br />

Betriebssystemen, die der wesentliche Teil der Konkretisierung paralleler Systeme<br />

sind, behandelt. Insbesondere geht es um die Arbeitsspeicherverwaltung<br />

2


Schlichter, TU München 1.2. MOTIVATION<br />

(Hauptspeicherverwaltung, "main memory management"), die Prozessverwaltung<br />

und die Prozessorzuteilung sowie Mechanismen zur Kontrolle der Nebenläufigkeit.<br />

¯ Parallele Systeme können auf zentralen Hardwarekonfigurationen realisiert<br />

werden. Als Basis können aber auch verteilte, vernetzte Hardwarekonfigurationen<br />

dienen, so dass verteilte Rechensysteme entstehen, die heute durchweg<br />

im Einsatz sind. Es werden deshalb die grundlegenden Aspekte von verteilten<br />

Systemen behandelt, insbesondere die nachrichtenbasierte Prozesskommunikation,<br />

das Client-Server Modell und die Netzwerkprogrammierung.<br />

¯ Mit der rasanten Verbreitung des Internet und dessen Nutzung für private und<br />

geschäftliche Transaktionen (E-Commerce und E-Business) steigt der Bedarf<br />

an sicheren IT-Systemen. Der Abschnitt behandelt nach einigen verbreiteten<br />

Sicherheitslücken verschiedene Schutzmechanismen, wie Schutzmatrizen,<br />

Kryptosysteme und Authentifizierungsmechanismen.<br />

1.2 Motivation<br />

Aufgabe der Informatik ist es, Rechensysteme zu entwickeln und diese Anwendern<br />

als leistungsfähige Hilfsmittel für Lösungen ihrer Informationsverarbeitungsprobleme<br />

zur Verfügung zu stellen. Diese Aufgabe ist vielgestaltig,<br />

weitreichend, kompliziert und komplex; sie führt im Zuge der Weiterentwicklung<br />

von Rechensystemen und im Zuge der wachsenden Nachfrage der Gesellschaft<br />

nach Information fortwährend auf neue Fragestellungen, für die nach Antworten<br />

gesucht werden muss. Sie hat zudem dazu geführt, dass sich große Bereiche der<br />

Industrie und der Wirtschaft mit dieser Aufgabe befassen. Im folgenden werden<br />

zunächst die wichtigsten Anforderungen, die mit der Entwicklung von Rechensystemen<br />

erfüllt werden sollen, in Kürze genauer erklärt.<br />

1.2.1 Anforderungen an Rechensysteme<br />

Rechensysteme sind offene, dynamische, technische Systeme mit Fähigkeiten zur<br />

Speicherung und zur Verarbeitung von Information, die für Anwendungen und<br />

Anwender nutzbar zur Verfügung gestellt werden sollen.<br />

Offenes System<br />

Ein Rechensystem R ist ein offenes System sagt zweierlei:<br />

3


Schlichter, TU München 1.2. MOTIVATION<br />

¯ R ist als System eine durch Zusammenfassung gebildete, abgegrenzte Einheit.<br />

Innen ist das, was zu R gehört, und außen ist das, was nicht zu R und damit zur<br />

Umgebung U(R) gehört.<br />

¯ R hat eine (offene) Schnittstelle, mit der Einwirkungen von U(R) auf R und<br />

Einwirkungen von R auf U(R) möglich sind.<br />

¯ Schnittstelle eines Rechensystems<br />

Umgebung<br />

U(R)<br />

Schnittstelle R - U(R)<br />

Rechensystem R<br />

¯ Sichten eines Rechensystems<br />

Es existieren verschiedene Sichten auf das Rechensystems R<br />

– Außensicht vs. Innensicht. Die Außensicht, die von außen die Eigenschaften<br />

der R-U(R) Schnittstelle zeigt, und die Innensicht, welche die inneren<br />

Eigenschaften von R zeigt.<br />

– Black-box Sicht vs. White-box Sicht. Das System ist ein schwarzer<br />

Kasten (black box): Das System wird als einzelner Gegenstand aufgefasst.<br />

Das System ist ein weißer Kasten (white box oder auch glass box): Für<br />

das Verständnis des Systems ist die Zusammensetzung in Subsysteme und<br />

Komponenten wichtig.<br />

– Sichten sind methodische Hilfsmittel für Systemanalysen:<br />

£ Komponenten haben Eigenschaften, die denen von Systemen entsprechen.<br />

Dies bedeutet, Komponenten können für sich als Systeme betrachtet<br />

werden.<br />

4


Schlichter, TU München 1.2. MOTIVATION<br />

£ Verbindungen zwischen Komponenten beschreiben Abhängigkeiten zwischen<br />

Komponenten.<br />

£ Aufteilungen liefern verfeinerte White-box Sichten.<br />

£ Zusammenfassungen und Abgrenzungen liefern Einheiten, für die Blackbox<br />

Sichten möglich sind.<br />

£ Rekursion bei der Entwicklung und Analyse von Rechensystemen. Die<br />

umrissene Vorgehensweise unter Anwendung der erklärten Systembegriffe<br />

ist für Analysen großer Systeme geeignet, wenn sie iterativ (rekursiv)<br />

angewandt wird; sie ist insbesondere dann geeignet, wenn sie induktiv<br />

angewandt werden kann. Die Möglichkeiten hierfür ergeben sich aus den<br />

Eigenschaften, die ein gegebenes System hat. Für ein Rechensystem R<br />

wird über diese Möglichkeiten bei der Entwicklung von R entschieden.<br />

Die Vorgehensweise bei der Entwicklung von R und die Vorgehensweise<br />

bei Analysen von R stehen also in engem Zusammenhang.<br />

Dynamisches System<br />

Eigenschaften des Rechensystems R ändern sich mit der Zeit<br />

Beschreibung des Verhaltens von R.<br />

In diesem Zusammenhang werden wir Beschreibungsmöglichkeiten kennenlernen,<br />

insbesondere Petrinetze. Diese dienen dazu das Verhalten von Prozessen und<br />

deren Interaktion zu spezifizieren. Ein Rechensystem erhält seine Fähigkeiten<br />

zu selbsttätigen Veränderungen seiner Eigenschaften mit entsprechenden Komponenten;<br />

demnach sind für R aktive und passive Komponenten zu unterscheiden:<br />

Mit seinen aktiven Komponenten führt R Aktionen aus, die Veränderungen der<br />

Eigenschaften von R bewirken; die passiven Komponenten sind Hilfsmittel für<br />

diese Aktionen.<br />

Technisches System<br />

Rechensystem ist mit hardware- und softwaretechnischen Mitteln realisiert. R<br />

ist entweder ein mit technischen Mitteln realisiertes, reales System oder ein<br />

künstliches, artifizielles System, das die Eigenschaften hat, die es mit seiner<br />

Entwicklung und mit seinen Weiterentwicklungen erhält.<br />

Informationsspeicherung und -verarbeitung<br />

5


Schlichter, TU München 1.2. MOTIVATION<br />

Information<br />

Daten<br />

Nachricht<br />

Wissen<br />

Information<br />

Repräsentation Interpretation<br />

Daten<br />

Daten sind elementare Fakten, Aussagen und Sachverhalte. Sie sind leicht<br />

zu strukturieren, leicht maschinell zu erfassen und leicht zu übertragen. Im<br />

Zusammenhang mit der Übertragung spricht man auch gerne von Nachrichten.<br />

Information sind Daten mit einer Bedeutung und einem Zweck; sie erfordert<br />

Analyse, Konsens bzgl. Semantik und Interpretation. Wissen ist Information<br />

in einem bestimmten, für den Menschen relevanten Kontext; es ist schwierig,<br />

Wissen zu strukturieren, schwierig maschinell zu erfassen und zu verarbeiten.<br />

Weiterhin ist es schwierig Wissen zu übertragen, da es oft nur implizit existiert<br />

(siehe auch das neue Forschungsgebiet Wissensmanagement bzw. "Knowledge<br />

Management").<br />

1.2.2 Struktur eines Rechensystems<br />

6


Schlichter, TU München 1.2. MOTIVATION<br />

Datenbank World Wide Web Email<br />

Shell Übersetzer Dateisystem<br />

Betriebssystem<br />

Maschinensprache<br />

Mikroprogramme / festverdrahtete Programme<br />

physische Komponenten und Geräte<br />

Anwendungsprogramme<br />

Systemprogramme<br />

Hardware<br />

In dieser Vorlesung werden wir uns besonders mit Aspekten der technischen Informatik<br />

beschäftigen, und zwar mit den Bereichen Hardware (Architektur, Maschinensprache)<br />

und Systemprogramme (Betriebssysteme, Assembler, Kommunikation<br />

in verteilten Systemen). Die Vorlesung ist als eine Einführung in diese Bereiche<br />

zu interpretieren; eine detailliertere Behandlung von Hardware, Systemprogramme<br />

und verteilte Systeme erfolgt in weiterführenden Vorlesungen des Hauptstudiums.<br />

Mikroprogramme dienen zur Realisierung der Maschinensprache; bei<br />

RISC-Rechnern (z.B. Sun Workstation) sind die Mikroprogramme oft festverdrahtet.<br />

¯ Darstellung von Programmen in maschinennaher Form für bestimmte Anwendungen<br />

auch heute noch unerläßlich, beispielsweise für den Übersetzerbau,<br />

eingebettete Systeme oder für systemnahe <strong>Programmierung</strong> in Teilen des Betriebssystems.<br />

Beispiele dafür sind Echtzeitanwendungen, aber auch Teile<br />

des Betriebssystems wie Nachrichtenaustausch, low-level Speicherverwaltung.<br />

Eingebettete Systeme sind in Autos oder Handies zu finden. Beispielsweise<br />

ist in modernen Autos bereits eine zwei- oder dreistelligen Anzahl von Prozessoren<br />

zu finden, die über einen internen Bus miteinander verbunden sind.<br />

¯ Thema der Vorlesung ist also maschinennahe <strong>Programmierung</strong>, systemnahe<br />

Programmentwicklung; nebenläufige ("concurrent") Ausführung von mehreren<br />

7


Schlichter, TU München 1.3. THEMEN DER VORLESUNG<br />

Teilabläufen Nichtdeterminismus. Dabei ergibt sich von selbst eine neue<br />

Qualität der <strong>Programmierung</strong>: Nebenläufigkeit, d.h. zwei oder mehrere<br />

Teilabläufe finden gleichzeitig statt, beispielsweise CPU (bzw. RK) und<br />

Drucker. Neue Qualität insofern, als Nebenläufigkeit auch Nichtdeterminismus<br />

enthält. Unter Nichtdeterminismus verstehen wir das willkürliche Auftreten<br />

von Abläufen und Ereignissen (bedingt durch Einflüsse wie Last, Interaktion<br />

mit Benutzer).<br />

1.3 Themen der Vorlesung<br />

Diese Vorlesung beschäftigt sich mit den technischen Aspekten von Rechensystemen<br />

und der Informationsverarbeitung, insbesondere der systemnahen <strong>Programmierung</strong>.<br />

Dabei werden sowohl nicht verteilte als auch verteilte Systeme betrachtet.<br />

1.3.1 Laufzeitmodell<br />

Bereitstellung eines indirekten Zugangs zur Rechnerhardware über eine Dienstschicht.<br />

Ziel dieser Schicht ist die Realisierung einer virtuellen Maschine. Virtualisierung<br />

kann sowohl zur Fehlervermeidung als auch zur Reduktion der Komplexität<br />

eingesetzt werden.<br />

¯ Die in den Diensten bereitgestellten Abstraktionen stellen einen Rahmen für<br />

die Organisation von Anwendungen zur Laufzeit dar, d.h. ein Laufzeitmodell.<br />

¯ Dienste des Laufzeitmodells: Systembedienung, Prozessmanagement, Prozessinteraktion,<br />

Datenhaltung, Gerätemanagement. Wichtige Fragestellungen der<br />

systemnahen <strong>Programmierung</strong> sind:<br />

a) welche Dienste gehören zu einem Laufzeitmodell?<br />

b) gibt es einen inneren Zusammenhang unter den Diensten?<br />

c) welche Dienstmenge ist unverzichtbar?<br />

d) wo werden die Dienste realisiert?<br />

Beispielsweise werden die Dienste im Betriebssystemkern oder als Systemprozesse<br />

realisiert, die im Benutzermodus ("user mode") ablaufen.<br />

¯ elementare Abstraktionen eines Laufzeitmodells. Prozesse sind dynamische<br />

Objekte, die Aktivitäten in einem Rechensystem repräsentieren. Jeder<br />

Prozess ist definiert durch einen Adressraum A, eine darin gespeicherte<br />

Handlungsvorschrift H in Form eines sequentiellen Programms und einen<br />

8


Schlichter, TU München 1.3. THEMEN DER VORLESUNG<br />

Aktivitätsträger T, der mit der Handlungsvorschrift verknüpft ist und sie<br />

ausführt. Der Aktivitätsträger T wird oft auch als "Thread" bezeichnet. Das<br />

Tripel (A, H, T) repräsentiert einen sequentiellen Prozess.<br />

Elemente des Laufzeitmodells<br />

– Adressräume = Abstraktion eines physischen Speichers. Unter einem<br />

Adressraum versteht man einen von der Speichertechnologie und den<br />

beschränkten Ausbaumöglichkeiten physischer Speicher unabhängigen<br />

virtuellen Speicher. Adressräume verschiedener Prozesse sind gegeneinander<br />

abgeschottet.<br />

Threads ablaufen.<br />

Innerhalb eines Adressraums können ein oder mehrere<br />

– Threads = Abstraktion eines physischen Prozessors. Ein Thread ist der<br />

Träger einer sequentiellen Aktivität, die durch die Ausführung eines dem<br />

Thread zugeordneten Programms (Handlungsvorschrift) bestimmt ist.<br />

– Prozessinteraktion. Prozessinteraktion kann entweder speicherbasiert,<br />

d.h. es gibt gemeinsame Speicherbereiche, auf die die Prozesse<br />

(Threads) zugreifen, oder nachrichtenbasiert ablaufen. Im ersten Fall<br />

sind Mechanismen zur Synchronisation der Zugriffe auf den gemeinsamen<br />

Speicherbereich notwendig, um Inkonsistenzen zu vermeiden. Im letzten Fall<br />

haben die Prozesse getrennte Adressräume. Sie tauschen Informationen über<br />

Nachrichten aus. Dieser Ansatz wird vor allem in verteilten Rechensystemen<br />

verwendet, wo Prozesse über ein Rechnernetz miteinander kommunizieren.<br />

1.3.2 Inhaltsübersicht<br />

Im einzelnen werden in der Vorlesung die folgenden Themen behandelt:<br />

1. hardwarenahe Programm-/Datenstrukturen anhand der Modellmaschine MI.<br />

Neben der MI Rechnerarchitektur werden einige Maschinenbefehle sehr kurz<br />

behandelt. Auch wird die Programmaufbereitung mit Assembler, Binder und<br />

Lader kurz andiskutiert. Ein Aspekt ist auch noch die Darstellung von ein-<br />

/mehrdimensionalen Felder im Arbeitsspeicher.<br />

2. Übergang von sequentiellen Systemen zu parallelen Systemen: Verhaltensbeschreibungen<br />

mit Hilfe von Spuren und Petrinetzen, Synchronisationskonzepte.<br />

Hier steht vor allem die speicherbasierte Prozessinteraktion im<br />

Vordergrund, d.h. das gemeinsame Nutzen von Daten. Hier kommen<br />

Semaphore und Monitore zum Einsatz. Ein wichtiger Aspekt ist die Behandlung<br />

von Verklemmungen, d.h. Prozesse blockieren sich gegenseitig.<br />

9


Schlichter, TU München 1.4. LITERATURÜBERSICHT<br />

3. grundlegende Betriebssystemkonzepte: Prozessverwaltung,<br />

Prozessorzuteilung, Arbeitsspeicherverwaltung, Dateisysteme. Bei der<br />

Arbeitsspeicherverwaltung steht vor allem der virtuelle Speicher in Form der<br />

Seitenadressierung im Vordergrund. Die Modellmaschine MI unterstützt auch<br />

die virtuelle Adressierung auf der Basis von Seiten und Kacheln. Bei Dateisystemen<br />

wird neben allgemeinen Anforderungen auch ein Schichtenmodell kurz<br />

vorgestellt.<br />

4. Kommunikation in verteilten Systemen: Client-Server-Paradigma, RPC,<br />

Netzwerkprogrammierung. In diesem Abschnitt steht die nachrichtenbasierte<br />

Prozessinteraktion im Vordergrund, und zwar die Kommunikation über Ports<br />

und Sockets.<br />

5. Sicherheit in Rechensystemen: Schutzmechanismen, Zugriffskontrolllisten,<br />

Capability-Listen, Kryptographie, Authentifizierungsdienst Kerberos. In<br />

diesem Abschnitt steht die Sicherheit in Rechensystemen im Vordergrund, und<br />

zwar sowohl in lokalen als auch in verteilten Systemen.<br />

1.4 Literaturübersicht<br />

Literatur, die als Basis für die Vorlesung verwendet wird.<br />

1.4.1 Begleitend zur Vorlesung<br />

¯ Jürgen Nehmer, Peter Sturm, "Systemsoftware - Grundlagen moderner<br />

Betriebssysteme", dpunkt.verlag, 2001<br />

¯ Andrew S. Tanenbaum, "Modern Operating Systems", Prentice Hall, 2001<br />

1.4.2 Begleitend zur Übung<br />

U. Borghoff, T. Gasteiger, A. Schmalz, P. Weigele, H.J. Siegert, "MI - Eine<br />

Maschine für die Informatikausbildung", TU Bericht 1987<br />

1.4.3 Weiterführende Literatur<br />

¯ Manfred Broy, "Informatik - Eine grundlegende Einführung", Springer-Verlag,<br />

1998<br />

10


Schlichter, TU München 1.4. LITERATURÜBERSICHT<br />

¯ George Coulouris, Jean Dollimore, Tim Kindberg, "Distributed Systems -<br />

Concepts and Design", Addison-Wesley, 2001<br />

¯ Claudia Eckert, "IT-Sicherheit: Konzepte - Verfahren - Protokolle", Oldenbourg<br />

Verlag, 2003<br />

¯ Elliotte Rusty Harold, "Java Network Programming", O'Reilly, 2000<br />

¯ Ralph Morelli, "Java, Java, Java - Object-Oriented Problem Solving", Prentice<br />

Hall, 2000<br />

¯ Andrew S. Tanenbaum, "Computernetzwerke", Prentice Hall, 2000<br />

¯ Andrew S. Tanenbaum, Marten van Steen, "Verteilte Systeme - Grundlagen und<br />

Paradigmen", Pearson Studium, 2003<br />

11


Kapitel 2<br />

Rechner und hardwarenahe<br />

Programme<br />

In diesem Abschnitt werden hardwarenahe Programme und Datenstrukturen<br />

für einfache Rechensysteme behandelt. Die Systeme sind zentralisiert, führen<br />

sequentielle Berechnungen aus und bestehen aus wenigen Komponenten.<br />

2.1 Fragestellungen<br />

Dieser Abschnitt wird relativ kurz gehalten, da einige Themen bereits in<br />

einführenden Vorlesungen zu Informatik angesprochen wurden. Insbesondere<br />

werden nachfolgende Themen angesprochen.<br />

¯ prinzipieller Aufbau eines einfachen sequentiellen Rechners.<br />

¯ Basisfähigkeiten sequentieller Rechner. Beispiele für Basisfähigkeiten sind der<br />

Befehlsgrundzyklus sowie der vorhandene Befehlsvorrat.<br />

¯ kurze Einführung in die Modellmaschine MI.<br />

¯ Programmaufbereitung in die Modellmaschine MI.<br />

¯ hardwarenahe Datenstrukturen (z.B. Linearisierung von Feldern).<br />

2.2 von Neumann Rechner<br />

Die Entwicklungsgeschichte von Rechensystemen wurde durch den sogenannten<br />

von Neumann-Rechner geprägt.Dieses Konzept dient auch weiterhin als Basis für<br />

12


Schlichter, TU München 2.2. VON NEUMANN RECHNER<br />

die meisten Rechnerarchitekturen, wobei es jedoch einige Variationen gibt, um<br />

gewisse Schwächen zu umgehen (z.B. mehrere Bussysteme).<br />

Arbeitsspeicher<br />

Eingabewerk Steuerwerk<br />

Ausgabewerk<br />

¯ Komponenten<br />

Rechenwerk<br />

Prozessor<br />

(CPU)<br />

– Arbeitsspeicher (ASP, oft auch als Hauptspeicher bezeichnet): Speicherung<br />

der Programme und ihrer Daten. ASP besteht aus einem Feld von adressierbaren<br />

Speicherzellen. Problem: Variable höherer Programmiersprachen sind<br />

typisiert; Arbeitsspeicher ist jedoch nicht typisiert, sondern nur Folge von<br />

Bits. Es gibt einige Rechnerarchitekturen, die einen typisierten Arbeitsspeicher<br />

(eine sogenannten "tagged memory") unterstützen, z.B. Burroughs<br />

Rechner.<br />

– Steuerwerk: Steuerung des Ablaufs der Befehle eines Programms. Jeder<br />

Maschinenbefehl ist ein Paar (Opcode, Operanden). Die Aktionen, die das<br />

Steuerwerk ausführt werden mit Hilfe von Maschinenbefehlen spezifiziert.<br />

Ein Maschinenbefehl besteht aus dem OpCode und den Operanden. Der<br />

OpCode spezifiziert die Operation (abgesehen von Sprungbefehlen), die<br />

dann im Rechenwerk ausgeführt werden soll. Das Steuerwerk enthält<br />

Informationen über den Status des Programmablaufs (z.B. Befehlszähler)<br />

und Einrichtungen für die Erzeugung der Steuersignale zur Ausführung der<br />

einzelnen Befehle (Steuersignale für den Steuerbus beim Zugriff auf Ein-/<br />

Ausgabewerk bzw. ASP).<br />

Aufgaben des Steuerwerks<br />

1. Holen von Maschinenbefehlen aus dem Arbeitsspeicher.<br />

13


Schlichter, TU München 2.3. ARCHITEKTUR SEQUENTIELLER RECHNER<br />

2. Dekodieren der Befehle.<br />

3. Holen der Operanden der Befehle aus dem Arbeitsspeicher. Dies erfordert<br />

je nach Situation die geeignete Adressrechnung zur Bestimmung der<br />

relevanten Speicherzellen im Arbeitsspeicher. Sowohl das Steuerwerk<br />

als auch das Rechenwerk führen Maschinenbefehle aus. Letzteres<br />

die Rechenoperationen, während das Steuerwerk Maschinenbefehle zur<br />

Steuerung des Programmablaufes ausführt (z.B. Sprungbefehle).<br />

– Rechenwerk: Ausführung von Rechenoperationen, die während des Ablaufs<br />

durchgeführt werden müssen.<br />

– Eingabewerk: Einlesen des Programms und der Daten in den Arbeitsspeicher.<br />

– Ausgabewerk: Ausgabe von Daten aus dem Arbeitsspeicher. Ein-<br />

/ Ausgabewerk werden bei der MI zu einem EA-Prozessor (EAP)<br />

zusammengefasst. Ein MI-Rechner kann mehrere EA-Prozessoren besitzen.<br />

¯ Ein Prozessor (Rechnerkern) ist die Zusammenfassung des Steuer- und<br />

Rechenwerks. Register dienen zur Speicherung von Zwischenergebnissen.<br />

Daneben gibt es in Rechnerimplementierungen ein Bussystem, das die<br />

einzelnen Komponenten untereinander verbindet. Ein MI-Rechner kann bis zu<br />

vier Rechnerkern besitzen; sie werden mit RK0 bis RK3 bezeichnet.<br />

2.3 Architektur sequentieller Rechner<br />

Der von Neumann Rechner ist ein logisches Modell für einen Rechner. Mit Hilfe<br />

von physischen Komponenten wird dieses Modell implementiert.<br />

2.3.1 Blockdiagramm für eine Architektur<br />

14


Schlichter, TU München 2.3. ARCHITEKTUR SEQUENTIELLER RECHNER<br />

Prozessor<br />

(Register)<br />

Adressbus<br />

Datenbus<br />

Steuerbus<br />

Arbeitsspeicher<br />

Monitor Tastatur Festplatte<br />

Graphik<br />

Controller<br />

Keyboard<br />

Controller<br />

Festplatten<br />

Controller<br />

¯ Der Bus verbindet die einzelnen Rechnerkomponenten. Er wird exklusiv<br />

genutzt. Allgemeines Problem: Synchronisation konkurrierender Zugriffe<br />

verschiedener Komponenten auf den exklusiv nutzbaren Bus. Der Bus besteht<br />

aus einer Menge von Verbindungsleitungen.<br />

– Adressbus (16, 32 oder 64 bit): Übergabe von Adressen. Der Adressbus<br />

addressiert einzelne Speicherzellen des Arbeitsspeichers (gegebenenfalls<br />

auch Speicherzellen in den Ein-/Ausgabewerken). Die Breite des Adressbus<br />

legt die Menge der maximal adressierbaren Speicherzellen fest, z.B. können<br />

mit einem 32 bit breiten Adressbus maximal 2 32 Zellen angesprochen werden<br />

(insgesamt 4 GByte).<br />

– Datenbus (32 oder 64 bit): Übermittlung von Daten.<br />

– Steuerbus: Menge von Steuerleitungen, z.B. Lese- oder Schreibbefehl an<br />

ASP. Der Steuerbus dient zur Koordination der Lese- und Schreibzyklen<br />

zwischen Prozessor und den anderen Komponenten.<br />

¯ Kommunikation zwischen Komponenten<br />

Nachfolgendes Beispiel zeigt die Aktionen, die ein Prozessor (Rechnerkern<br />

RK) und der Arbeitsspeicher ausführen, um Daten vom Arbeitsspeicher über<br />

den Bus zum Prozessor zu übertragen.<br />

Arbeitsspeicher<br />

Daten<br />

15<br />

Prozessor<br />

(RK)


Schlichter, TU München 2.3. ARCHITEKTUR SEQUENTIELLER RECHNER<br />

– Ablauf der Kommunikation<br />

Die Komponenten arbeiten nicht mit einem gemeinsamen Takt, sondern<br />

unabhängig voneinander.<br />

1. RK legt die ASP-Adresse der gewünschten Dateneinheit (16, 32 oder 64<br />

bit Umfang) auf den Adressbus.<br />

2. RK legt das Signal "Lesen" auf eine bestimmte Leitung im Steuerbus.<br />

3. RK legt das Signal "Adresse gültig" auf eine bestimmte Leitung im<br />

Steuerbus. Damit wird erreicht, dass die Adresse erst gelesen wird, wenn<br />

alle Adressleitungen und Signale gültig sind (d.h. stehen).<br />

4. ASP ist passiv, "hört" aber auf Adress- und Steuerbus mit.<br />

5. ASP erkennt, dass eine Adresse gültig ist und prüft, ob er mit dieser<br />

Adresse gemeint ist. Falls ja, führe Schritte 6 - 12 aus. Dies sieht er<br />

anhand von der spezifizierten Adresse; später werden die Aufteilung der<br />

Adressbereiche noch gesondert behandelt. Wenn ASP durch die Adresse<br />

nicht angesprochen ist, erfolgt keine weitere Aktion.<br />

6. ASP prüft das Transportrichtungssignal im Steuerbus (es erkennt das<br />

Signal "Lesen").<br />

7. ASP legt die (adressierten) Daten auf den Datenbus.<br />

8. ASP legt das Signal "Daten bereit" auf eine bestimmte Leitung im<br />

Steuerbus.<br />

9. RK wartet, bis das Signal "Daten bereit" erscheint. Er weiß dann, dass die<br />

Daten auf dem Datenbus gültig sind und übernimmt diese.<br />

10. RK legt das Signal "Daten übernommen" auf eine bestimmte Leitung im<br />

Steuerbus.<br />

11. ASP deaktiviert daraufhin den Datenbus und das Signal "Daten bereit" .<br />

12. Sobald das Signal "Daten bereit" vom ASP weggenommen wird,<br />

deaktiviert der RK die von ihm verwendeten Adress- und Steuerleitungen.<br />

Der Bus ist wieder im Grundzustand und kann damit von einem anderen<br />

Prozessor verwendet werden.<br />

– Protokoll<br />

Zwischen den beteiligten Kommunikationspartnern existiert ein vereinbartes<br />

Verhaltensprotokoll.<br />

£ Verhaltensprotokolle in der Praxis: in der Vorlesung (Finger heben),<br />

Straßenverkehrsordnung, etc.<br />

£ Definition<br />

Ein Ablauf aus Aktions- und Kommunikationsschritten zwischen Kommunikationspartnern<br />

heißt ein Protokoll. Das Protokoll definiert auch<br />

16


Schlichter, TU München 2.3. ARCHITEKTUR SEQUENTIELLER RECHNER<br />

Syntax, Semantik und die Reihenfolge der auszutauschenden Information.<br />

Protokolle dienen zur Festlegung der Kommunikation zwischen Komponenten.<br />

Sie spielen eine wichtige Rolle für effiziente Kommunikation<br />

und Kooperation. Es besteht eine hoher Standardisierungsbedarf, da die<br />

beteiligten Komponenten dasselbe Protokolle verwenden müssen. Protokolle<br />

spielen im Bereich der Rechnernetze eine sehr wichtige Rolle.<br />

£ Der oben geschilderte Ablauf ist ein Busprotokoll. Das obige Busprotokoll<br />

macht keine Annahmen über die Geschwindigkeit der Arbeit bei<br />

den beteiligten Partnern (d.h. es besteht asynchrones Arbeiten ohne<br />

Zeitgrenzen). Deshalb sind immer wieder Quittungen eines Partners<br />

erforderlich, in denen er mitteilt, dass er einen Schritt abgeschlossen hat.<br />

2.3.2 Befehlsgrundzyklus<br />

Die Reihenfolge der Ausführung der Maschinenbefehle wird durch den<br />

Befehlsgrundzyklus des Prozessors festgelegt.<br />

ÛÐ ØÖÙ ß<br />

ÓÐ Ò Ò ×ØÒ Å× ÒÒÐ Ö×× ×ØÑÑØ ÙÖ <br />

Ð×ÞÐÖ È<br />

×ØÑÑ Ò ÇÔÓ × Ð×<br />

×ØÑÑ ÙÒ Ð ÇÔÖÒÒ × Ð× Ò ÚÓÒ<br />

Ö Ö××ÖÙÒ×ÖØ<br />

Ö Ò Ð Ù× Ñ×Ø ÙÖ × Ê ÒÛÖ<br />

× ÐØ Ò Ð×ÞÐÖ ÓÖØ ÞÙÑ Æ ÓÐÖÐ<br />

<br />

Der Fortschaltung und damit der Wert des neuen Befehlszählers ist abhängig von<br />

der Länge des aktuellen Befehls (Operanden) bzw. von dem Sprungziel.<br />

¯ Ein Berechnungsschritt besteht aus den beiden Phasen: Befehlsholphase und<br />

Befehlsausführungsphase. Damit ergibt sich die Pipeline<br />

hole<br />

Befehl<br />

dekodiere<br />

Befehl<br />

führe<br />

Befehl aus<br />

In modernen Prozessoren werden die einzelnen Phasen der Pipeline durch<br />

getrennte Hardwarekomponenten durchgeführt. Dadurch ist eine verschränkte<br />

Ausführung von mehreren Befehlen möglich. Verschiedene Befehle können<br />

sich gerade in unterschiedlichen Phasen befinden, z.B. Befehl 1 wird<br />

gerade ausgeführt, während Befehl 2 dekodiert wird und während die<br />

17


Schlichter, TU München 2.3. ARCHITEKTUR SEQUENTIELLER RECHNER<br />

Befehlsholeinheit gerade den Befehl 3 aus dem Arbeitsspeicher holt. Dadurch<br />

ist eine Beschleunigung des Ablaufes möglich. Besondere Aufmerksamkeit<br />

benötigen Sprünge, da sie die serielle Ausführung von Maschinenbefehlen<br />

unterbrechen.<br />

Animation Pipelining<br />

siehe online Version<br />

¯ Die Ausführung des Befehls erfolgt auf einer niedrigeren Abstraktionsebene,<br />

der Mikroebene.<br />

¯ Der Grundzyklus hat einen festen Zeittakt, der die Dauer eines Zyklus festlegt.<br />

2.3.3 E/A Architekturvarianten<br />

Die Ein-/Ausgabewerke können durch unterschiedliche Architekturvarianten<br />

realisiert werden. Dabei muss insbesondere das unterschiedliche Zeitverhalten<br />

der peripheren Geräte und der Komponenten wie Prozessor und Arbeitsspeicher<br />

berücksichtigt werden. Periphere Geräte sind um ein Vielfaches langsamer.<br />

E/A-Controller können entweder direkt an den Prozessorbus oder über einen<br />

getrennten Gerätebus an den Prozessorbus angeschlossen werden.<br />

¯ Speicherbasierte E/A<br />

Bei dieser Variante entsprechen E/A-Controller in ihrer Ansteuerung herkömmlichen<br />

Speicherbausteinen. Der Prozessor kann Register der E/A-Controller<br />

nicht von normalen Speicherzellen unterscheiden.<br />

Prozessor<br />

Arbeitsspeicher<br />

E/A Controller E/A Controller<br />

Durch normale Lese- und Schreiboperationen und ohne Einschränkungen<br />

bei den verwendeten Adressierungsarten kann auf die Register der E/A-<br />

Controller zugegriffen werden. Diese E/A-Architekturvariante wird bei der<br />

Modellmaschine MI verwendet.<br />

¯ E/A-Bus Controller<br />

Bei dieser Variante werden die peripheren Geräte nicht direkt an den schnellen<br />

Prozessorbus angeschlossen, sondern über einen separaten Gerätebus.<br />

18<br />

Bus


Schlichter, TU München 2.3. ARCHITEKTUR SEQUENTIELLER RECHNER<br />

Prozessor<br />

E/A Controller E/A Controller E/A Controller<br />

Arbeitsspeicher<br />

E/A-Bus<br />

Controller<br />

Prozessorbus<br />

Gerätebus<br />

Bekannte Gerätebussysteme sind PCI, ISA und IEEE 1394 (FireWire) im PC-<br />

Bereich. Der Bus-Controller kann eine Reihe von Grundfunktionen, z.B.<br />

die Bearbeitung von Interrupts und DMA-Aufträgen, für alle angeschlossenen<br />

Geräte-Controller übernehmen.<br />

2.3.4 Architektur der MI<br />

Die Modellmaschine MI basiert auf der real-existierenden VAX-Architektur (von<br />

Digital Equipment). Sie umfasst bis zu 4 Prozessoren; Adressbus und Datenbus<br />

haben jeweils 32 bit.<br />

Prozessor<br />

RK0<br />

Adressbus<br />

Datenbus<br />

Steuerbus<br />

Prozessor<br />

RK3<br />

Plattenspeicher 1<br />

Arbeitsspeicher<br />

Plattenspeicher 2<br />

E/A<br />

Controller1<br />

Terminal<br />

Drucker<br />

E/A<br />

Controller2<br />

E/A-Controller werden bei der MI auch als E/A-Prozessoren bezeichnet. Bei der<br />

MI hat jeder Prozessor eine Nummer 0 - 3. Der Bus kann jeweils nur von einem<br />

Rechnerkern betrieben werden. Die MI-Architektur ist eine Multiprozessor-<br />

19


Schlichter, TU München 2.4. BEFEHLSVORRAT EINES RECHNERS<br />

Architektur.<br />

¯ Die Prozessoren der MI (RK0 - RK3) haben jeweils 16 Register R0 -<br />

R15 mit jeweils 32 Bit. Das Register R15 ist der Befehlszähler PC. Das<br />

Register R14 ist der Kellerpegel SP. Der Kellerpegel dient zur Verwaltung des<br />

Kellerbereichs im Arbeitsspeicher bei Unterprogrammaufrufen. Daneben gibt<br />

es noch einige Sonderregister, z.B. für die Ansteuerung der aktuellen Seiten-<br />

Kacheltabelle. Moderne Prozessoren umfassen sehr viel mehr Register. Ziel ist<br />

die Reduzierung von Arbeitsspeicherzugriffen, um den Bus als Flaschenhals zu<br />

umgehen.<br />

¯ R14 und R15 sind vom Benutzer nicht frei verwendbar. Die übrigen Register<br />

können aus Sicht der MI frei verwendet werden.<br />

¯ R0 - R15 sind symbolische Adressen.<br />

2.4 Befehlsvorrat eines Rechners<br />

Das Verhalten eines Rechensystems R wird von den Aktionen bestimmt, die<br />

der Prozessor P von R ausführt, und dieses Verhalten wird gestaltet, indem die<br />

Befehle, die P ausführen soll, festgelegt und zur Ausführung bereitgestellt werden.<br />

In jedem Grundzyklus führt P eine atomare Aktion aus, die mit einem Befehl<br />

spezifiziert ist, und die eine Veränderung des Zustands von R bewirkt.<br />

2.4.1 Charakterisierung der Befehle<br />

Ein Befehl ist eine elementare Verarbeitungs- oder Berechnungsvorschrift. Als<br />

solche legt ein Befehl fest, was getan werden soll, und womit es getan werden<br />

soll; zudem legt ein Befehl, wie schon erklärt wurde, seinen Nachfolgerbefehl<br />

fest. Ein Befehl besteht aus einer Operations- und einer Operandenspezifikation.<br />

¯ Ein Befehlswort ist die binäre Darstellung eines Befehls in einem Rechner. Ein<br />

Befehlswort ist ein Paar<br />

– Operationsteil: was soll getan werden?<br />

– Operandenteil: womit soll es getan werden? Der Operandenteil wird oft<br />

auch als Adressteil bezeichnet, weil Operanden überwiegend mit Adressen<br />

spezifiziert werden.<br />

20


Schlichter, TU München 2.4. BEFEHLSVORRAT EINES RECHNERS<br />

¯ Befehlsvorrat<br />

Der Befehlsvorrat (Instruktionssatz) eines Rechners ist die Menge der<br />

Befehle, die der Prozessor des Rechners ausführen kann. Aus der<br />

angegebenen Struktur von Befehlen ergibt sich, dass der Befehlsvorrat mit den<br />

jeweils zugelassenen Operationsspezifikationen und den ihnen zugeordneten<br />

Operandenspezifikationen festgelegt ist; dabei bedeutet zugelassen, dass der<br />

Prozessor die entsprechende Repräsentation als Befehlswort interpretieren und<br />

den Befehl ausführen kann.<br />

¯ Befehlsklassen<br />

Befehle des Befehlsvorrats lassen sich in 3 Hauptgruppen einteilen:<br />

1. Transportbefehle: dienen dem Austausch von Daten (Binärwörtern)<br />

zwischen Registern, Arbeitsspeicher und E/A-Geräten.<br />

2. Rechenbefehle: dienen zur Verknüpfung von Binärwörtern, z.B. Arithmetik-,<br />

Logik- und Schiebeoperationen.<br />

3. Steuerbefehle: dienen zur Steuerung der Reihenfolge der Befehlsausführungen,<br />

z.B. unbedingte und bedingte Sprünge.<br />

¯ Getrieben von den hardware- und softwaretechnischen Fortschritten und von<br />

Erweiterungen ihrer Einsatzgebiete entstanden in der Folgezeit Rechner mit<br />

wachsenden Befehlsvorräten und mit komplizierteren Befehlen. Dieser Trend<br />

verstärkte sich, als in den 60-er Jahren die Rechner für wissenschaftliche und<br />

für kommerzielle Anwendungen, die bis dahin nebeneinander entwickelt wurden,<br />

zu sog. Rechnerfamilien (Rechner mit unterschiedlichen Leistungsmerkmalen<br />

aber einem allen Familienmitgliedern gemeinsamen Befehlsvorrat)<br />

zusammengeführt wurden. Dieser Trend setzte sich allgemein bis in die<br />

80-er Jahre und darüber hinaus bis heute fort. Diese Rechner werden mit<br />

CISC (für Complex Instruction Set Computer) charakterisiert. Sie haben Befehlssätze<br />

mit 250-350 Befehlen (Operationen) und vielen, zum Teil komplizierten<br />

Adressierungsarten.<br />

In den 80-er Jahren begann die Entwicklung von Rechnern mit bewusst<br />

klein gewählten Befehlsvorräten, etwa 100 Befehlen, und wenigen, einfachen<br />

Adressierungsarten, die mit RISC (für Reduced Instruction Set Computer)<br />

charakterisiert werden. Zur Begründung für RISC wurden CISC-<br />

Befehlsstatistiken ausgewertet. Sie zeigten, dass 95% der ausgeführten Befehle<br />

lediglich 25% der Befehle des Befehlsvorrats nutzen. Dieses Ergebnis ist<br />

insbesondere darauf zurückzuführen, dass nur ein kleiner Teil der Maschinenprogramme,<br />

die ausgeführt werden, von Hand als hardwarenahe Programme<br />

entwickelt werden; sie sind vielmehr die Ergebnisse von Transformationen von<br />

Programmen, die in höheren Programmiersprachen entwickelt werden.<br />

21


Schlichter, TU München 2.4. BEFEHLSVORRAT EINES RECHNERS<br />

Diese Argumente, die damals zur Begründung für RISC benutzt wurden, gelten<br />

heute verstärkt.<br />

– CISC = Complex Instruction Set Computer; ca. 250 - 350 Operation; z.B.<br />

Intel Pentium, Modellmaschine MI<br />

– RISC = Reduced Instruction Set Computer; ca. 100 Operation; z.B. Sun<br />

Sparc<br />

– Während CISC komplexe Befehle unterstützt, werden diese bei RISC durch<br />

eine Menge einfacher Befehle ersetzt;<br />

ÁË Ð<br />

<br />

ÊÁË Ð<br />

ÄÇ Ê<br />

ÄÇ Ê<br />

Ê Ê<br />

ËÌÇÊ Ê <br />

Die Wirkung ist S[a3] = S[a1] + S[a2]. Dabei bezeichnet S[a3] die<br />

Speicherzelle, deren Adresse a3 ist. Der Inhalt der mit a1 und a2<br />

adressierten Speicherzellen wird addiert und der Speicherzelle mit Adresse<br />

a3 zugewiesen. Man spricht im Zusammenhang mit RISC oft auch von einer<br />

Load und Store Architektur.<br />

2.4.2 Aufbau Maschinenbefehle<br />

Ein Maschinenbefehl gliedert sich in einen Operations- und einen Operandenteil<br />

(am Beispiel der MI); der Operandenteil kann u.U. fehlen;<br />

mnemonische Zeichen<br />

Datentyp/Kennung<br />

(Operationsteil, Operandenspezifikation)<br />

1-4 teilig mit<br />

Ausdrücken<br />

Å× ÒÒÐ ÇÔÖØÓÒ×ØÐ <br />

ÇÔÖØÓÒ×ØÐ ßÇÔÖÒÒ×ÔÞ <br />

¯ Der Operationsteil spezifiziert die Operation, die Kennung, und die Anzahl<br />

der Operanden. Letztere Information wird vom Assembler automatisch<br />

hinzugefügt; sie muss nicht vom Programmierer angegeben werden. Die<br />

Kennung ist wichtig bei den unterschiedlichen Adressierungsarten. Die<br />

Kennung definiert den Typ und die Länge der Operanden (LOP) in Bytes:<br />

22


Schlichter, TU München 2.4. BEFEHLSVORRAT EINES RECHNERS<br />

B Byte: 1<br />

H Halbwort: 2<br />

W Wort: 4<br />

F 32 bit Gleitpunktzahl: 4<br />

D 64 bit Gleitpunktzahl: 8<br />

Bei den Kennungen wird zwischen W und F unterschieden, weil bei bestimmten<br />

Operationen die Kennung nicht nur eine Angabe über die Länge der Operanden,<br />

sondern auch über die Art des Operanden enthalten muss. Beispielsweise ist<br />

für das Kopieren von Daten die Angabe der Länge ausreichend, aber bei der<br />

Addition muß auch noch die Angabe, ob ganze Zahlen oder Gleitpunktzahlen<br />

addiert werden sollen, dazukommen.<br />

¯ Die Operanden werden entweder direkt spezifiziert oder durch eine Vorschrift<br />

zur Bestimmung (Adressrechnung) angegeben. Bei der Modellmaschine MI<br />

lautet die Reihenfolge der Operanden stets so, dass das Ziel als letztes<br />

angegeben wird.<br />

¯ Maschinenadressen<br />

Der Arbeitsspeicher besteht aus einer Folge von fortlaufend nummerierten<br />

Bytezellen, denen jeweils Adressen zugeordnet sind. Man spricht hier von<br />

Maschinenadressen.<br />

Speicher<br />

0 7 0 7<br />

Adressraum a a+1<br />

Die Nummerierung beginnt bei 0; die höchste Nummer hängt vom Ausbau des<br />

physikalischen Speichers ab. Die Nummer der Bytes entsprechen jeweils den<br />

Maschinenadressen. Falls bei der MI eine Dateneinheit angesprochen wird,<br />

die mehr als ein Byte umfasst, dient immer die Adresse des ersten Bytes als<br />

Adresse der Dateneinheit. Die nachfolgenden Bytes der Dateneinheit haben<br />

immer höhere Adressen; sie werden jedoch nicht explizit spezifiziert. Eine<br />

Speicherzelle umfasst jeweils ein Byte; die Bits einer Speicherzelle b werden<br />

mit b 0 bis b 7 bezeichnet (von links nach rechts betrachtet).<br />

– Die Menge der möglichen Maschinenadressen ist der Maschinenadressraum.<br />

Prozesse sind ja Instanzen eines ablaufenden Programms. Prozesse<br />

haben ihre eigenen Adressen mit sogenannten Prozess- bzw. Programmadressen.<br />

Zu einem späteren Zeitpunkt wird eine Abbildung zwischen Pro-<br />

23


Schlichter, TU München 2.4. BEFEHLSVORRAT EINES RECHNERS<br />

grammadressen und Maschinenadressen vorgestellt, die Seitenadressierung.<br />

Sie ist ein wichtiger Teil des Betriebssystems.<br />

– S[a] ist der Wert der durch a adressierten Speicherzelle.<br />

– Über den Adressbus des Rechners werden Maschinenadressen übertragen.<br />

– Bei der Modellmaschine MI ist eine gültige Maschinenadresse<br />

£ einem Arbeitsspeicherbereich, oder<br />

£ einem Register eines EA-Prozessors (EA-Register) zugeordnet. Falls<br />

beides nicht zutrifft, ist die Maschinenadresse ungültig. Die Verwendung<br />

einer ungültigen Adresse führt zu einem Speicherschutzalarm, und damit<br />

zu einer Unterbrechung des in Ausführung befindlichen Prozesses. Die<br />

normalen MI-Maschinenbefehle können sowohl zur Adressierung des<br />

Arbeitsspeichers als auch zur Adressierung der EA-Register verwendet<br />

werden.<br />

¯ Aufbau des Maschinenadressraums der MI<br />

24


Schlichter, TU München 2.4. BEFEHLSVORRAT EINES RECHNERS<br />

¯ Operandenspezifikation<br />

H'0000 0000'<br />

H'000F FFFF'<br />

H'0010 0000'<br />

H'1FFF FFFF'<br />

H'2000 0000'<br />

H'3FFF FFFF'<br />

H'4000 0000'<br />

H'FFFF FFFF'<br />

1 MB Arbeitsspeicher<br />

Ausbau<br />

Arbeitsspeicher<br />

Erweiterungen<br />

(1 MB - 512 MB)<br />

Bereich, in dem über<br />

festgelegte Adressen<br />

die Register der EA-<br />

Prozessoren<br />

zugänglich sind<br />

keine Zuordnung<br />

ÇÔÖÒÒ×ÔÞ <br />

ÖØ Ö××ÖÙÒ <br />

ÙÒÑØØÐÖÖ ÇÔÖÒ <br />

Ê×ØÖÖ××ÖÙÒ <br />

ÖÐØÚ Ö××ÖÙÒ <br />

ÒÖØ Ö××ÖÙÒ <br />

ÒÞÖØ ÖÐØÚ Ö××ÖÙÒ <br />

ÒÞÖØ ÒÖØ Ö××ÖÙÒ <br />

ÃÐÐÖÖ××ÖÙÒ<br />

Im weiteren wird die Notation der Modellmaschine MI verwendet.<br />

– Direkte Adressierung<br />

Man spricht in diesem Zusammenhang auch von einer absoluten Adresse.<br />

Der Operand zeigt auf eine Stelle im Speicher, wo der Wert des Operanden<br />

25


Schlichter, TU München 2.4. BEFEHLSVORRAT EINES RECHNERS<br />

gespeichert ist.<br />

ÖØ Ö××ÖÙÒ <br />

Ù×ÖÙ Ö ÒÞ Ð <br />

ÁÒØØÓÖ ß ßÚÓÖÞ ÒÐÓ× ÒÞ Ð<br />

Ò <br />

Der Ort des Operanden wird durch seine Adresse angegeben; dabei sind<br />

symbolische Adressen (Identifikatoren) zugelassen. Symbolische Adressen<br />

sind frei wählbare Bezeichner für Speicherzellen. Der Definitionsbereich<br />

einer symbolischen Adresse ist das Programm, in dem es definierend<br />

auftritt. Ein Bezeichner tritt in einer Operandenspezifikation eines Befehls<br />

anwendend auf.<br />

£ Beispiele<br />

MOVE H 107, a + 315 Wirkung: S[a+315] = S[107]<br />

MOVE H 205 + 7, H'F1' Wirkung: S[241] = S[212]<br />

Es werden jeweils Halbwörter betrachtet, d.h. es werden jeweils 2 Byte<br />

transportiert.<br />

ADD W 101, 35, b Wirkung: S[b] = S[101] + S[35]<br />

Hier werden die Operanden als Wörter, d.h. mit 4 Byte betrachtet<br />

– Unmittelbarer Operand<br />

Ein unmittelbarer Operand ("immediate operand") steht im Befehl selbst.<br />

ÙÒÑØØÐÖÖ ÇÔÖÒ <br />

Á ßÐØÔÙÒØÞÐ Ù×ÖÙ Ö ÒÞ Ð<br />

Für unmittelbare Operanden ist keine Adresse im Arbeitsspeicher oder die<br />

Adresse eines Registers definiert.<br />

£ Beispiele<br />

MOVE B I 2, a2 Wirkung: S[a2] = 2 als Byte<br />

ADD W I H'FFOO', a2 , a3 Wirkung: S[a3] = H'FFOO' + S [a2]<br />

– Registeradressierung<br />

Die Register des Prozessors sind ausgezeichnete Speicherplätze. Operanden<br />

können aus Registern kommen und Ergebnisse können in Registern abgelegt<br />

werden. Da Zugriffe auf Register wesentlich schneller (es ist kein Transfer<br />

über den Bus notwendig) erfolgen als Zugriffe auf den Arbeitsspeicher,<br />

werden Zwischenergebnisse oder häufiger benötigte Werte tunlichst in<br />

Registern gehalten. Die Register werden durch einen symbolischen<br />

Registernamen bezeichnet. Moderne Architekturen haben sehr viel mehr<br />

Register als die Modellmaschine MI. Der Bus wird gerne als der Flaschenhals<br />

der von Neumann Architektur bezeichnet. Um dieses Problem weiter<br />

zu reduzieren, werden in heutigen Architekturen neben einer großen<br />

Registermenge zunehmend auch Prozessor-Caches verwendet.<br />

26


Schlichter, TU München 2.4. BEFEHLSVORRAT EINES RECHNERS<br />

Ê×ØÖÖ××ÖÙÒ ÊÜ<br />

ÊÜ Ê Ê Ê Ê Ê ËÈÈ<br />

Es wird der Wert des angesprochenen Registers verwendet.<br />

£ Es gilt: SP = R14 und PC = R15.<br />

£ Register werden auch im Zusammenhang mit der relativen, der indirekten<br />

und der indizierten Adressierung benutzt.<br />

– Relative Adressierung<br />

ÖÐØÚ Ö××ÖÙÒ <br />

ßÙ×ÖÙ Ö ÒÞ Ð ÊÜ<br />

ÒÞÖØ ÖÐØÚ Ö××ÖÙÒ <br />

ÖÐØÚ Ö××ÖÙÒÁÒÜÒ<br />

ÁÒÜÒ ÊÜ<br />

Die Funktion !adr entspricht einem Inhaltsoperator. Die Relativadressierung<br />

ist mit der Basis Rx und der angegebenen ganzen Zahl als<br />

Relativadresse zu verstehen.<br />

£ Steht auf Operandenstelle der Ausdruck "z+!Rx", so wird die Zahl<br />

z zum Wert des Registers Rx addiert und das Ergebnis als Adresse<br />

interpretiert, d.h. Operand = S[z + Wert von Rx].<br />

£ Steht auf Operandenstelle der Ausdruck "z+!Rx/Ry/", so werden<br />

die Zahl z, der Wert des Registers Rx und LOP * Wert des Registers<br />

Ry addiert und das Ergebnis als Adresse interpretiert. LOP ist die<br />

Länge des Operanden, z.B. 1 für B, 2 für H und 4 für W.<br />

£ Die relative Adressierung eignet sich sehr gut für den Zugriff von Feldern.<br />

£ Beispiel<br />

Es sei eine Feld a mit den Elementen a[1], a[2], ..., a[10] in<br />

aufeinanderfolgenden Speicherzellen abgelegt. Die Elemente sind von<br />

der Kennung W, d.h. 4 Byte lang. Das Element a[j] soll in Register R5<br />

gebracht werden. Die Adresse des ersten Elements a[1] stehe bereits in<br />

Register R0 und der Index j des gewünschten Elements in R1. Zur Lösung<br />

wird ein Befehl benötigt:<br />

ÅÇÎ Ï Ê Ê Ê<br />

-4 muß subtrahiert werden, da das Feld ab 1 durchgezählt ist; der Ausdruck<br />

R0 /R1/ verweist auf das Element j+1 und nicht auf das Element j.<br />

27


Schlichter, TU München 2.4. BEFEHLSVORRAT EINES RECHNERS<br />

Speicher<br />

R0<br />

R1<br />

a[1] a[2] a[j] a[10]<br />

– Indirekte Adressierung<br />

Bei der indirekten Adressierung (auch Adresssubstitution) entsteht in einem<br />

ersten Schritt die Adresse einer Speicherzelle. In dieser Speicherzelle steht<br />

nicht direkt der gewünschte Wert, sondern die Adresse des gewünschten<br />

Wertes. Man substituiert also beim Holen des Operanden zweimal.<br />

ÒÖØ Ö××ÖÙÒ <br />

ÖÐØÚ Ö×× ÊÜ<br />

ÒÞÖØ ÒÖØ Ö××ÖÙÒ <br />

ÒÖØ Ö××ÖÙÒÁÒÜÒ<br />

ÁÒÜÒ ÊÜ<br />

Die indirekte Adressierung wurde erstmals in der PERM (Programmgesteuerte<br />

Elektronische Rechenanlage München) verwirklicht (Erfinder:<br />

Schecher). !!Rx ist als Abkürzung für !(!Rx) zu sehen.<br />

£ Steht auf Operandenstelle der Ausdruck "!(z+!Rx)", so gilt:<br />

S[ S[z + Wert von Rx]]<br />

Die Zahl z wird zum Wert des Registers Rx addiert und das<br />

Ergebnis als Adresse a1 interpretiert. Der Inhalt der mit a1 adressierten<br />

Speicherzelle wird als Adresse einer Speicherzelle interpretiert, deren<br />

Wert der gesuchte Operand ist.<br />

£ Steht auf Operandenstelle der Ausdruck "!(z+!Rx)/Ry/", so gilt:<br />

S[ S[z + Wert von Rx] + LOP*Wert von Ry]<br />

LOP ist wieder die Länge des Operanden, z.B. 1 für B, 2 für H und 4 für<br />

W.<br />

£ Beispiel<br />

ÅÇÎ Ï Þ Ê Ê Ê<br />

Schritte für die Adressrechnung<br />

1. Relativadresse: a1:= z + (Wert in R3);<br />

2. dann indirekte Adresse: a2 := S[a1];<br />

3. dann Indizierung: a3:= a2 + (Wert in R4) * LOP;<br />

4. dann ab Operandenadresse a3 den (Wort-)Operand w holen: w := S[a3];<br />

anschließend wird w in Register R5 gespeichert.<br />

28<br />

R5


Schlichter, TU München 2.4. BEFEHLSVORRAT EINES RECHNERS<br />

a1<br />

a2<br />

a3<br />

a2<br />

w<br />

Wert von<br />

R4*LOP<br />

– Kelleradressierung<br />

Die Kelleradressierung dient zur Speicherung von Daten vor allem bei<br />

Unterprogrammaufrufen und der Blockstrukturen von Programmen.<br />

ÃÐÐÖÖ××ÖÙÒ ÊÜ ÊÜ<br />

Diese Adressierungsart ist vorwiegend für den Zugriff auf kellerartig<br />

angeordnete Elemente gedacht. Der Keller wächst von größeren Adressen<br />

zu kleineren Adressen. Der Kellerpegel zeigt auf die Adresse des letzten<br />

belegten Bytes im Keller, dies ist auch die Adresse des letzten Elementes<br />

im Keller. Der aktuelle Kellerpegel befindet sich in dem angegebenen<br />

Register (meist wird SP als Register verwendet). Das Register wird entweder<br />

vor der Adressberechnung dekrementiert oder nach der Adressberechnung<br />

inkrementiert, und zwar um den Wert LOP gemäß Kennung im Befehl.<br />

29


Schlichter, TU München 2.4. BEFEHLSVORRAT EINES RECHNERS<br />

Adresse<br />

kleiner<br />

größer<br />

wachsender<br />

Keller<br />

belegter Keller<br />

-!Rx entspricht der Kelleroperation push<br />

!Rx+ entspricht der Kelleroperation pop<br />

2.4.3 Befehle der MI<br />

-!<br />

!+<br />

Nachfolgend werden exemplarisch einige MI Befehle kurz vorgestellt. Eine<br />

detaillierte Darstellung der verfügbaren Maschinenbefehle befindet sich im MI<br />

Manual.<br />

Transportbefehle<br />

ÅÇÎ ßÀÏ ÏÖÙÒ Ë ℄ Ë ℄<br />

ÅÇÎÆ ßÀÏ ÏÖÙÒ Ë ℄ Ë ℄<br />

ÄÊ ßÀÏ ÏÖÙÒ Ë ℄ <br />

Der Befehl MOVE B R1, 201 transportiert das letzte Byte des Registers R1<br />

nach der Speicherzelle 201. Bei MOVEN wird eine negative Zahl gebildet;<br />

hier ist sofort ersichtlich, daß W und F unterschieden werden müssen, weil -<br />

x für eine ganze Zahl x anders auszuführen ist als für eine Gleitpunktzahl x.<br />

Weitere Transportbefehle sind PUSHR, der die Register R0 bis R14 der MI in den<br />

Keller speichert (wobei der Kellerpegel, d.h. SP, jeweils erhöht wird), sowie der<br />

entsprechende Befehl POPR, der die Werte vom Keller entfernt und in die Register<br />

lädt (der Kellerpegel wird erniedrigt). Die Register werden in der Reihenfolge<br />

R14 - R0 im Keller abgelegt, und in umgekehrter Reihenfolge aus dem Keller<br />

entfernt.<br />

30


Schlichter, TU München 2.4. BEFEHLSVORRAT EINES RECHNERS<br />

Rechenbefehle<br />

ÇÊ ßÀÏ ß <br />

ÏÖÙÒ Ë ℄ Ë ℄ ÓÖ Ë ℄ ØÛ× ÐÓ× <br />

ÇÔÖØÓÒ<br />

ßÀÏ ß <br />

ÏÖÙÒ Ë ℄ Ë ℄ Ë ℄<br />

Logische Operationen wie z.B. OR oder ANDNOT werden gerne verwendet, um<br />

einzelne Bits zu setzen oder mit Hilfe einer Maske einzelne Bits auszublenden.<br />

¯ Shiftbefehl<br />

ËÀ ÏÖÙÒ Ë ℄ Ë ℄ ÚÖ× ÓÒ<br />

ÙÑ Ë ℄ ÇÔÖÒÒ Ñ Ï ÓÖÑØ<br />

– S[a1] 0<br />

Verschiebung nach links um S[a1] Stellen. Von rechts werden 0-Bits<br />

nachgezogen. Nach links hinausgeschobene Bits gehen verloren.<br />

£ Arithmetische Interpretation: Multiplikation von S[a2] mit 2 S[a1]<br />

(Überlauf möglich).<br />

– S[a1] 0<br />

Verschiebung nach rechts um |S[a1]| Stellen. Von links werden vorzeichengleiche<br />

Bits nachgezogen (d.h. der Wert von b bestimmt, welche Bitwerte<br />

0<br />

von links nachgezogen werden). Nach rechts hinausgeschobene Bits gehen<br />

verloren.<br />

£ Arithmetische Interpretation: Division von S[a2] durch 2 |S[a1]|<br />

– S[a1] = 0<br />

keine Verschiebung; Wirkung wie MOVE W a2, a3<br />

¯ Rotationsbefehl<br />

ÊÇÌ ÏÖÙÒ Ë ℄ Ë ℄ ÖÓØÖØ ÙÑ<br />

Ë ℄ ÇÔÖÒÒ Ñ Ï ÓÖÑØ<br />

Während man SH auch als arithmetischen Shift bezeichnet, nennt man ROT<br />

einen logischen Schiebebefehl.<br />

– S[a1] 0<br />

Verschiebung nach links um S[a1] Stellen. Nach links hinausgeschobene Bits<br />

werden von rechts nachgezogen.<br />

31


Schlichter, TU München 2.4. BEFEHLSVORRAT EINES RECHNERS<br />

– S[a1] 0<br />

Verschiebung nach rechts um |S[a1] |Stellen. Nach rechts hinausgeschobene<br />

Bits werden von links nachgezogen.<br />

– S[a1] = 0<br />

keine Verschiebung; Wirkung wie MOVE W a2, a3<br />

¯ Anwendungsbeispiel 1<br />

Aufgabe: prüfe, ob eine ganze Zahl x im W Format gerade ist. Prüfung, ob<br />

x gerade ist, durch Prüfung des Bit x[b ] = 0; Ungerade bedeutet, dass das<br />

31<br />

letzte Bit gleich 1 ist. Eine Möglichkeit ist z.B. das Ausblenden aller Bits bis<br />

auf b ; dann Abfrage mit JGE (Jump Greater Equal), d.h. ist die Bedingung<br />

31<br />

größer/gleich 0.<br />

ÊÇÌ Á Ü Ê ÙÑ Ò Ö Ø× Ñ ÃÖ× ÛÖ ÞÙÑ<br />

ÎÓÖÞ Ò<br />

 ×ÔÖÒ ÐÐ× Ð ÔÓ×ØÚ ×Ø ÁÒ<br />

×Ñ ÐÐ ×Ø Ð Ö<br />

¯ Anwendungsbeispiel 2<br />

Aufgabe: In Abhängigkeit eines Zeichenausschnitts im Zeichen z sollen<br />

entsprechende Operationen ausgeführt werden. Das entspricht einer Fallunterscheidung.<br />

Ein Beispiel dafür sind in höheren Programmiersprachen die sogenannten<br />

case-Anweisungen.<br />

Zeichen z<br />

b 0<br />

b 1<br />

b 2<br />

b 3<br />

b 4<br />

k sei der betrachtete Ausschnitt mit k = 0,...,7<br />

Die zugehörigen Bearbeitungssequenzen stehen ab den Adressen: f0, f1, ...,<br />

f7, d.h. in Abhängigkeit des Wertes von k wird an die entsprechende Stelle f i<br />

gesprungen. Realisierung mit Hilfe einer Sprungkaskade.<br />

– Vereinbarung der Sprungziele<br />

Ï Ö×× Ö ÖØÙÒ××ÕÙÒÞ <br />

Ï Ö×× Ö ÖØÙÒ××ÕÙÒÞ <br />

Ï Ö×× Ö ÖØÙÒ××ÕÙÒÞ <br />

32<br />

b 5<br />

b 6<br />

b 7


Schlichter, TU München 2.4. BEFEHLSVORRAT EINES RECHNERS<br />

– Programmausschnitt<br />

ÄÊ Ï Ê ×ØÞ Ê×ØÖ Ê ÞÙÖ <br />

ÅÇÎ Þ Ê Ê ℄ Ê <br />

℄ Þ<br />

ËÀ Á Ê Ê ÖØÑØ× Ö ËØ Ò Ö Ø×<br />

ÙÑ Þ Ù ÈÓ×ØÓÒ ÞÙ<br />

ÔÐØÞÖÒ<br />

ËÀ Á Ê Ê ËØ Ò ÐÒ× ÙÑ ÛÐ× <br />

ÏÓÖØÖÒÞ ÞÙ ÖÐØÒ ×Ø<br />

ÙÑ ÄÇÈ <br />

ÅÇÎ Ê ×× Ö ËÔÖÙÒÞÐÖ××Ò Ò <br />

Ê<br />

Ï Ê Ê Ö×× Ö ÖØÙÒ××ÕÙÒÞ Ò<br />

Ê<br />

ÂÍÅÈ Ê ×ÔÖÒ ÞÙÖ ÖØÙÒ××ÕÙÒÞ<br />

Steuerbefehle<br />

I.a. werden Befehle in der Reihenfolge ihrer Programmaufschreibung ausgeführt.<br />

Sprünge spezifizieren einen Nachfolgebefehl, der i.a. in der Programmaufschreibung<br />

nicht unmittelbar auf den Sprungbefehl folgt. Es wird zwischen unbedingten<br />

und bedingten Sprüngen unterschieden.<br />

¯ ÂÍÅÈ unbedingter Sprung an die Adresse a1; der Befehlszähler PC wird mit<br />

a1 besetzt<br />

¯ Bedingungen<br />

Die Bedingungen von bedingten Sprüngen sind durch die jeweiligen Werte von<br />

vier speziellen 1-Bit-Registern bestimmt.<br />

N negativ<br />

Z zero (0)<br />

V Überlauf (overflow)<br />

C Übertrag (carry)<br />

Die Register können zu dem Spezialregister CC = (N, Z, V, C) zusammengefasst<br />

werden.<br />

– Die Ausführung des Befehls führt mit x = S[a1]+S[a2] zu<br />

folgender Besetzung von CC<br />

CC = (x 0, x == 0, ?, ?) wobei sich die Werte für ? gemäß der<br />

Arithmetik ergeben.<br />

33


Schlichter, TU München 2.5. HARDWARENAHE PROGRAMME<br />

Es gilt dabei S[a3] = x. Wenn x 0 ist, ergibt sich N = 1, sonst gilt N=0.<br />

Falls x gleich 0 ist, wird Z mit 1 besetzt.<br />

– Die Ausführung des Befehls ÅÇÎ Ï <br />

Besetzung von CC<br />

führt mit x = S[a1] zu folgender<br />

CC=(x0, x == 0, 0, C), d.h. der Wert von C bleibt unverändert.<br />

– Die Ausführung des Befehls ÅÈ Ï führt mit x = S[a1] und y = S[a2]<br />

zu folgender Besetzung von CC. ÅÈ ist ein Vergleichsbefehl, der die Werte<br />

der mit a1 und a2 bezeichneten Operanden vergleicht.<br />

CC = (x y, x == y, V, C), d.h.<br />

unverändert.<br />

die Werte von V und C bleiben<br />

¯ bedingte Sprünge<br />

Die Bedingungen bzgl. des Sprungs beziehen sich auf die Werte im<br />

Spezialregister CC. Die nachfolgende Liste von Sprüngen ist nur eine Auswahl<br />

der in der MI verfügbaren Sprünge (siehe MI Manual). Bei den 1-Bit-Registern<br />

geht es insbesondere darum, ob das entsprechende Bit gesetzt ist oder nicht.<br />

– Beispiele von Sprungbefehlen<br />

ÂÉ ÒÙÒ <br />

ÂÆ ÒÙÒ <br />

 ÒÙÒ Æ ÓÖ <br />

ÂÎ ÒÙÒ Î<br />

 ÒÙÒ <br />

Animation MI Programm<br />

siehe online Version<br />

2.5 Hardwarenahe Programme<br />

Zur Erleichterung werden hardwarenahe Programme für ein Rechensystem nicht<br />

als ausführbare Maschinenprogramme (Folge von Befehlswörtern) realisiert,<br />

sondern mit Hilfe von Assemblerprogrammen.<br />

2.5.1 Definitionen<br />

Maschinenschnittstelle<br />

Als Maschinenschnittstelle bezeichnet man die Gesamtheit aller Datenobjekte und<br />

Operationen der reinen Hardwarearchitektur (auch Programmierschnittstellen der<br />

Maschine).<br />

34


Schlichter, TU München 2.5. HARDWARENAHE PROGRAMME<br />

¯ Folge von Maschinenbefehlen ist auf dieser Ebene eine Folge von Binärzeichen.<br />

Auf dieser Ebene müsste man insbesondere die Befehle der Maschine als reine<br />

Folge von Binärzeichen (Befehlswörter) schreiben; diese Schnittstelle ist sehr<br />

programmier-unfreundlich.<br />

Assemblerschnittstelle<br />

Die Assemblerschnittstelle ist die eigentliche maschinennahe (konkrete) Programmierschnittstelle.<br />

Sie erlaubt, alle Befehle, Adressen und Datenobjekte der reinen<br />

Hardware darzustellen.<br />

¯ Verwendung von Namen für Adressen und Operationen. Assemblersprachen<br />

sind eine geringfügige Erweiterung von reinen Maschinensprachen. Zur<br />

bequemeren Nutzung werden u.a. symbolische Adressen (z.B. Identifikatoren)<br />

und symbolische Namen für Operationen (z.B. ADD für Addition) verwendet.<br />

Für die Beschreibung der MI (insbesondere der MI Befehle) haben wir bereits<br />

diese Schnittstelle zugrunde gelegt.<br />

Assembler<br />

Ein Assembler ist ein Programm, das die Aufgabe hat,<br />

1. Assemblerbefehle in Maschinencode zu transformieren,<br />

2. symbolischen Namen Maschinenadressen zu zuweisen, sowie<br />

3. ein Objektprogramm zu erzeugen.<br />

2.5.2 Programmaufbereitung<br />

Hier beschäftigen wir uns mit dem Programmieren auf der Assemblerschnittstelle.<br />

Ausgangspunkt sind Assembler-Programme (z.B. MI-Programme), und wir<br />

versuchen zu klären, was ist noch zu tun, um ein ausführfähiges Programm<br />

im Arbeitsspeicher zu haben. Wir wollen eine grobe Vorstellung der<br />

Funktion eines Assemblers, Binders und Laders vermitteln. Binder/Lader<br />

sind i.d.R. Bestandteil des Betriebssystems. Hier steht nicht die Konstruktion<br />

solcher Komponenten (Systemprogrammierung), sondern deren Aufgaben und<br />

Funktionen im Vordergrund.<br />

35


Schlichter, TU München 2.5. HARDWARENAHE PROGRAMME<br />

Programm<br />

z.B. Java Programm<br />

Assembler<br />

Programm<br />

Compiler<br />

Assembler<br />

Bindemodul Bindemodul<br />

Lademodul<br />

Maschinenbefehle mit<br />

relativen Adressen<br />

Maschinenprogramm im<br />

Arbeitsspeicher<br />

Binder<br />

Lader<br />

symbolische Bezüge nach<br />

außen<br />

offene Referenzen<br />

In der Vorlesung werden nur allgemeine Assembler-Funktionen behandelt. Für<br />

den MI-Assembler gilt, dass er die Aufgaben Assemblieren und Binden in sich<br />

vereinigt, also ein ausführbares Ladeobjekt erstellt. (vgl. MI-Handbuch, Kapitel<br />

4).<br />

2.5.3 MI Assemblerprogramm<br />

Ein Assemblerprogramm besteht aus einer Menge von Segmenten, die jeweils<br />

durch ein Trennzeichen (z.B. Neuzeile) voneinander getrennt sind (siehe MI<br />

Manual für die Grammatik des MI Assemblers).<br />

36


Schlichter, TU München 2.5. HARDWARENAHE PROGRAMME<br />

×ÑÒØ ×ÑÒØÒÑ Ë ß<br />

ÐÖ×× ÌÖÒÒÞ<br />

ßßÅÖ ÒÛ×ÙÒÌÖÒÒÞ<br />

ÐÖ×× ÚÓÖÞ ÒÐÓ× ÒÞ Ð<br />

ÅÖ ÆÑ ßÌÖÒÒÞ<br />

ÒÛ×ÙÒ ××ÑÐÖ×ØÙÖÙÒ <br />

Å× ÒÒÐ ØÒÒØÓÒ<br />

ÌÖÒÒÞ ßÃÓÑÑÒØÖÆÙÞÐ<br />

Die Assemblersteuerung enthält Anweisungen an den Assembler, z.B. die<br />

Bekanntmachung von Variablen in anderen Segmenten durch die Importund<br />

Exportanweisungen. Ablageadressen sind hier als Programmadressen zu<br />

verstehen. Anwenderprogramme arbeiten mit virtuellen Speicheradressen, die<br />

bei der Ausführung des Programms in Maschinenadressen umgewandelt werden,<br />

d.h. der virtuelle Arbeitsspeicher wird auf den realen Arbeitsspeicher abgebildet.<br />

Die Segmentierung dient der Einteilung eines Programms in Einheiten (genannt<br />

Segmente) aus Benutzersicht (z.B. für gleichartige Zugriffsrechte!).<br />

¯ Komponenten eines systemnahen Programms<br />

Ein systemnahes Programm besteht aus drei Komponenten: dem Anweisungsteil,<br />

dem Datenteil und dem Registerteil.<br />

im Arbeitsspeicher<br />

im Prozessor<br />

Datenteil<br />

Anweisungsteil<br />

Registerteil<br />

Variable<br />

Programmcode<br />

invariant<br />

Hilfsvariable<br />

Der Anweisungs- und Datenteil sind explizit definiert, während der Registerteil<br />

implizit für jedes Programm existiert. Die implizite Definition bedeutet, dass<br />

die Registerwerte (mit Ausnahme des PC) bei Ablaufbeginn undefiniert sind.<br />

Die Anfangswerte des Datenteils werden i.a. durch das Programm vorgegeben.<br />

Der Anweisungs- und Datenteil werden je nach Art der Daten im Keller bzw.<br />

auf der Halde gespeichert.<br />

37


Schlichter, TU München 2.5. HARDWARENAHE PROGRAMME<br />

2.5.4 Assembler Grundfunktionen<br />

Ein Assembler muss aus den Assemblerbefehlen den entsprechenden Maschinencode<br />

erzeugen, und anschließend das Objektprogramm generieren, wobei symbolische<br />

Namen auf Maschinenadressen abgebildet werden.<br />

Erzeugen von Maschinencode<br />

Beispiel<br />

Ö×× ÅÖ Ð<br />

Ï ÁÒÜ Ê<br />

ÁÒÜ <br />

¯ Aktionen bei der Erzeugung<br />

– Maschinencode für Operationsteil, z.B. in MI: Assemblerbefehl ADD W<br />

wird codiert als H'C1', falls nur 2 Operandenspezifikationen folgen.<br />

– Maschinencode für Operandenspezifikationen, z.B. in MI: R6 codiert als<br />

H'56'<br />

– Konvertieren von symbolischen Namen in Maschinenadressen, z.B. symbolischer<br />

Name Index auf Adresse 1033 abbilden<br />

– Konstruktion eines Maschinenbefehls im korrekten Format<br />

– Konvertieren von Konstanten in interne Maschinen-Repräsentationen z.B.<br />

EOF in H'454F46'. Hier ist die Zeichenkette "EOF" gedacht, und nicht endof-file.<br />

– Assembler-Steuerungsanweisung: Assembler Direktiven, z.B. bei MI RES,<br />

werden vom Assembler nicht transformiert, sondern interpretiert, z.B. als<br />

Auftrag, Speicherplatz zu reservieren.<br />

¯ Problem<br />

Abarbeiten des Quellprogramms Zeile für Zeile. Befehle können jedoch<br />

Vorwärts-Referenzen enthalten, z.B. im Beispiel Definition des symbolischen<br />

Namens Index erst nach Nutzung. Die korrekte Adresse der Vorwärts-Referenz<br />

ist bei dieser Vorgehensweise beim ersten Auftreten der Referenz noch nicht<br />

bekannt und es kann noch kein korrekter Code erzeugt werden.<br />

– Lösung<br />

Assembler macht 2 (oder mehr) Läufe (siehe Seite 40) (engl. "pass") über<br />

das Assemblerprogramm.<br />

38


Schlichter, TU München 2.5. HARDWARENAHE PROGRAMME<br />

£ 1-ter Lauf: Zuordnen von Maschinenadressen<br />

£ 2-ter Lauf: Codierung, d.h. Erzeugung der Maschinenbefehle<br />

Erzeugen des Objektprogramms<br />

Der Assembler schreibt den generierten Maschinencode in ein Objekt-<br />

Programm/Ladeobjekt (z.B. ".o" oder ".obj" Datei), das dann in den Speicher<br />

geladen und ausgeführt werden kann. Ein einfaches Objekt-Programm enthält unterschiedliche<br />

Klassen von Einträgen (z.B. gekennzeichnet mit einem speziellen<br />

Buchstaben), die unterschiedliche Informationen für den Binder/Lader zur Verfügung<br />

stellen.<br />

¯ Header Informationen<br />

Name des Programms, Startadresse (Hex), Länge des Programms (Hex),<br />

Einträge z.B. mit H gekennzeichnet. Bei MI enthält die erste Zeile des<br />

Objektprogramms: Startadresse, Anzahl der Zeichen in Segmentnamen,<br />

Segmentname<br />

¯ Text<br />

Maschinencode und Daten, Einträge z.B. mit T gekennzeichnet. Bei MI: keine<br />

extra Kennung und Code wird zeilenweise im Ladeprogramm gespeichert.<br />

¯ Ende<br />

Ende des Programms und Adresse der ersten auszuführenden Instruktion (Hex),<br />

Einträge z.B. mit E gekennzeichnet. Bei MI: letzte Zeile mit einem Punkt in<br />

erster Spalte.<br />

¯ Beispiel eines Ladeobjekts<br />

××ÑÐÖ Ó<br />

Ì×Ø Ë<br />

ÅÇÎ Ï Á À ËÈ<br />

ÂÍÅÈ ×ØÖØ<br />

ÞÙÖ× ÄÓØ<br />

Ì×Ø<br />

<br />

<br />

ÛØÖÖ Å× ÒÒ Ó<br />

Die erste Zeile spezifiziert die Startadresse H'0, die Länge 4 des Segmentnamens<br />

sowie den Segmentnamen selbst. Die 2. Zeile repräsentiert den Befehl:<br />

39


Schlichter, TU München 2.5. HARDWARENAHE PROGRAMME<br />

MOVE W I H'10000, SP. Die 3. Zeile entspricht JUMP start; die Adresse von<br />

start ergibt sich dabei durch AF19.<br />

Datenstrukturen des Assemblers<br />

Für die Transformation benötigt der Assembler im wesentlichen 2 Tabellen: eine<br />

Objekt-Code Tabelle und eine Symboltabelle. Beide Tabellen (OCT u. SYMT)<br />

werden normalerweise als Hashtabellen realisiert, auf OCT wird dann z.B. mit<br />

dem Befehl als Such-Schlüssel zugegriffen.<br />

¯ Objekt-Code Tabelle (OCT)<br />

Die Objekt-Code Tabelle enthält eine Zuordnung zwischen Maschinencode und<br />

Assemblerbefehl; diese Tabelle ist meist statisch fest. OCT kann auch weitere<br />

Informationen enthalten: z.B. Befehlslänge, Operandenzahl, Format.<br />

– MI: ÅÇÎ Ï entspricht H'A0' oder ÂÍÅÈ entspricht H'F1'<br />

¯ Symboltabelle (SYMT)<br />

Die Symboltabelle enthält die Zuordnung zwischen symbolischen Namen und<br />

Maschinenadressen; diese Tabelle kann auch weitere Informationen enthalten:<br />

z.B. Typ, Länge.<br />

– Der Assembler erzeugt die Symboltabelleneinträge während des ersten<br />

Laufs. Während des zweiten Laufs werden dann alle Namen, die in Operandenspezifikationen<br />

auftreten, durch die in der Symboltabelle eingetragene<br />

Adresse ersetzt.In die Symboltabelle werden auch die benutzerdefinierten<br />

Symbole (z.B. bei der MI durch EQU Anweisungen festgelegt) aufgenommen,<br />

zusammen mit dem Wert, der durch eine solche Anweisung für den<br />

symbolischen Namen festgelegt wird.<br />

2.5.5 Assemblerläufe<br />

Ein Assembler macht 2 (oder mehr) Läufe über das Assemblerprogramm.<br />

Nachfolgend werden kurz die Schritte eines einfachen Assemblers vorgestellt.<br />

Lauf 1<br />

Der Lauf 1 erzeugt ein Programm in einem Zwischenformat, das als Eingabe für<br />

Lauf 2 dient, insbesondere erfolgt eine Zuordnung von symbolischen Namen zu<br />

Maschinenadressen.<br />

40


Schlichter, TU München 2.5. HARDWARENAHE PROGRAMME<br />

1. Initialisiere Location Counter (Zähler) mit Startadresse, falls angegeben, sonst<br />

mit 0.<br />

2. Ersetze Operationsteil durch Maschinencode.<br />

3. Auftreten eines symbolischen Namens N in einem Befehl: Trage N in<br />

Symboltabelle ein, falls noch nicht in Tabelle.<br />

4. Falls eine Marke definierend auftritt:<br />

¯ Falls Name noch nicht in SYMT: Erzeuge SYMT-Eintrag mit Zählerstand<br />

¯ Falls Marke ohne Zählerstand schon drin: Eintrag des Zählerstands<br />

¯ Falls Marke mit Zählerstand schon drin: Fehler, da doppelte Namensvereinbarung<br />

5. Erhöhe Zähler um Länge der Instruktion (aus Op-Code zu entnehmen).<br />

6. Falls nicht Dateiende, lies nächste Zeile und gehe zu Schritt 2.<br />

Beispiel<br />

ÓÙÒØÖ ÅÖ Ð<br />

Ì×Ø Ë<br />

×ØÖØ<br />

ÂÍÅÈ ×ØÖØ<br />

¯ Beim Auftreten der Marke start in "ÂÍÅÈ ×ØÖØ" : Eintrag in Symboltabelle<br />

an Indexstelle i .<br />

ÁÒÜ ÆÑ Ö××<br />

×ØÖØ<br />

¯ Beim Auftreten der Definition Marke start in "start:" Eintrag des aktuellen<br />

Zählerstandes in Symboltabelle an Indexstelle i .<br />

ÁÒÜ ÆÑ Ö××<br />

×ØÖØ <br />

41


Schlichter, TU München 2.5. HARDWARENAHE PROGRAMME<br />

Lauf 2<br />

Der Lauf 2 des Assemblers erzeugt das Objekt-Programm<br />

1. Erzeuge Header-Eintrag und schreibe ihn in Objekt-Programm.<br />

2. Initialisiere ersten Text-Eintrag. Ein Texteintrag kann beispielsweise ein<br />

Maschinenbefehl sein.<br />

3. Falls symbolischer Name in Operandenspezifikation auftritt:<br />

¯ suche Name in SYMT<br />

¯ ersetze Name in Operand durch Adresse in SYMT<br />

¯ Falls Name nicht gefunden: trage 0 als Adresse ein und setze Flag: undefined<br />

Symbol<br />

4. Konstruiere korrekten Maschinenbefehl-Code.<br />

5. füge Code dem Text-Eintrag hinzu, falls noch Platz, sonst: schreibe Text-<br />

Eintrag in Objekt-Programm und erzeuge neuen Text-Eintrag.<br />

6. Falls noch nicht Programmende: lies nächste Zeile des Eingabe-Programms<br />

und führe Schritte 3 bis 6 durch.<br />

7. schreibe letzten Text-Eintrag in Objekt-Programm.<br />

8. schreibe End-Eintrag in Objekt-Programm.<br />

PC-relative Adressierung<br />

Ein Problem bei dieser Vorgehensweise ist, dass das Programm an den<br />

angegebenen Adressen zur Ausführung kommen muss Wunsch: verschiebbare<br />

Programme. Berechnen relativer Adressen durch Assembler, und zwar relativ zum<br />

PC. Dies wird auch von der MI unterstützt.<br />

¯ Idee<br />

Anstatt der Adresse an der der symbolische Name laut Symboltabelle zu finden<br />

ist: Angabe eines PC-relativen Displacements.<br />

42


Schlichter, TU München 2.5. HARDWARENAHE PROGRAMME<br />

¯ Vorgehen<br />

Zieladresse setzt sich zusammen aus Zähler (PC) und Displacement; PC<br />

Wert wird bereits nach dem Holen des Befehls erhöht; das muss bei der<br />

Adressrechnung berücksichtigt werden. Displacement bestimmt eine Adresse<br />

relativ zum Wert des Befehlszählers (PC).<br />

– Displacement x für Adresse des symbolischen Names muss berechnet<br />

werden: Zieladresse = PC + x<br />

– Beispiel: Vorwärtsverweis<br />

ÓÙÒØÖ ÅÖ Ð<br />

Ì×Ø Ë<br />

ÂÍÅÈ ×ØÖØ<br />

×ØÖØ<br />

Als Code für den Befehl Jump start ergibt sich folgender<br />

£ F1 = Code für ÂÍÅÈ<br />

£ PC-relative Adressierung: PC =Register 15 (R15), d.h. es ergibt sich AF<br />

(F = R15 und A für relative Adressierung)<br />

£ Berechnen des Displacements x mit PC + x = 00000045 (= Adresse von<br />

start)<br />

Æ Wert des PC nach Abarbeitung von F1 AF: 00000033 + 2 = 00000035.<br />

Der Sprungbefehl umfasst 2 Byte, d.h. der PC wird nach dem Holen des<br />

Befehls um 2 inkrementiert.<br />

Æ also: Displacement x = 10, damit sich die Zieladresse 00000045 ergibt<br />

£ Insgesamt ergibt sich als Maschinencode: F1 AF10<br />

¯ Vorteile der PC-relativen Adressierung<br />

– Verschiebbarkeit der Objektprogramme durch relative Adressierung. Der<br />

Lader hat dann die Aufgabe, dazu jeweils die absolute Startadresse hinzu<br />

zu addieren.<br />

– kurze Operanden: Register-relative Adressierung (in unserem Fall durch<br />

PC).<br />

¯ Bemerkung: One-Pass Assembler: es dürfen keine Vorwärts-Referenzen<br />

auftreten, d.h. es muss das Define-before-use Prinzip gelten.<br />

43


Schlichter, TU München 2.5. HARDWARENAHE PROGRAMME<br />

2.5.6 Binder und Lader<br />

Ein Assembler-Programm kann aus mehreren logischen Einheiten (MI: Segmente)<br />

bestehen, die vom Assembler als einzelne, unabhängige Einheiten (Bindemoduln)<br />

transformiert werden. In Informatik I/II wurde bereits Modularisierung<br />

als wichtiges Konstruktionsprinzip behandelt. Aspekte sind: Problem wird in<br />

Teilprobleme zerlegt, Bausteine als Lösung von Teilproblemen, Wiederverwendung<br />

von Bausteinen, Bibliotheken (engl. library). Modularisierung ist besonders<br />

bei der Entwicklung großer Programme sehr wichtig.<br />

Binder<br />

Der Binder (engl. linker) hat die Aufgabe, aus einer Menge von einzelnen<br />

Bindemoduln ein ausführfähiges Ladeprogramm zu erzeugen, indem die noch<br />

offenen externen Referenzen aufgelöst werden.<br />

¯ Binde-Module<br />

Der Assembler erzeugt Code, der jeweils relativ zum Modul-Anfang adressiert.<br />

Segment 1<br />

JUMP start<br />

Lade<br />

objekt 1<br />

Segment 2 Segment n<br />

Lade<br />

objekt 2<br />

start:<br />

assemblieren<br />

Lade<br />

objekt n<br />

Assemblermodule<br />

Bindemodule<br />

Das Zusammenfügen der einzelnen Segmente zu einem ausführfähigen<br />

Programm ist die Aufgabe des Binders (Linker).<br />

– Externe Referenzen<br />

In einem Modul M i können Referenzen auf Daten/Marken auftreten, wobei<br />

die Daten/Marken in einem anderen Modul M j definiert werden. Beispiel:<br />

Marke start wird in Segment 1 verwendet, und erst in Segment n definiert.<br />

44


Schlichter, TU München 2.5. HARDWARENAHE PROGRAMME<br />

Solche Referenzen heißen externe Referenzen. Assembler kann Referenzen<br />

nicht auflösen, Assembler besitzt keine Informationen darüber, wo sich die<br />

einzelnen Segmente zur Ausführungszeit im Arbeitsspeicher befinden.<br />

– Behandlung externer Referenzen<br />

Für jede externe Referenz erzeugt der Assembler Informationen, die<br />

es dem Binder ermöglicht, aus den Einzelmoduln ein ausführfähiges<br />

Gesamtprogramm zu erzeugen, d.h. die Referenzen (siehe Seite 47)<br />

aufzulösen. Module können unabhängig assembliert werden: keine Vorgabe<br />

über zeitliche Reihenfolge.<br />

£ Der Programmierer gibt durch spezielle Assembler-Direktiven für jeden<br />

Modul an, welche Symbole, Namen und Marken des Moduls von außen<br />

verwendet werden können, d.h. exportiert werden (in MI durch EXP bzw.<br />

EXPORT Direktive).<br />

£ Extern referenzierte Symbole in einem Modul, sogenannte importierte<br />

Symbole, müssen durch Assembler-Steuerungsanweisungen im Modul<br />

markiert werden (in MI: IMP oder IMPORT Direktive).<br />

£ Assembler erzeugt ausgehend von diesen Steuerinformationen spezielle<br />

Einträge im Objekt-Programm.<br />

Æ Für exportierte Symbole: ein Eintrag (gekennzeichnet z.B. durch ein<br />

D (=define)), der den Namen und die relative Adresse des Symbols<br />

umfasst. Aufbau des Define-Eintrag:<br />

"Kennung D, Name des exportierten Symbols, relative Adresse des<br />

Symbols im definierenden Segment".<br />

Æ Für importierte Symbole: ein Eintrag (gekennzeichnet z.B. durch ein R<br />

(=refer)), der den Namen des importierten Symbols umfasst. Adressen<br />

können hierfür noch nicht eingetragen werden. Aufbau des Refer-<br />

Eintrag:<br />

"Kennung R, Name des importierten Symbols".<br />

£ Findet der Assembler eine externe Referenz, so trägt er in dem<br />

erzeugten Code die Adresse 0 ein. Gleichzeitig erzeugt er einen<br />

Modifikations-Eintrag (gekennzeichnet z.B. durch ein M (=modify)) im<br />

Objektprogramm, der für den Binder die benötigte Information enthält:<br />

Angabe, welches Auftreten der Referenz zu modifizieren ist und<br />

Name des externen Symbols.<br />

Auftreten bezieht sich hier auf die Angabe in der Operandenspezifikation,<br />

wo die externe Referenz auftritt. Aufbau Modifikations-Eintrag:<br />

"Kennung M, Startadresse des zu modif. Adressfeldes, importiertes<br />

Symbol".<br />

45


Schlichter, TU München 2.5. HARDWARENAHE PROGRAMME<br />

Lader<br />

Ein Lader (engl. loader) ist ein Systemprogramm, das die Aufgabe hat,<br />

Objektprogramme in den Speicher zu laden und deren Ausführung anzustoßen.<br />

¯ Eigenschaften<br />

In einem System ist i.d.R. nur ein Lader vorhanden, so dass Programme<br />

unterschiedlicher Quellsprachen in ein einheitliches Objektprogramm-Format<br />

transformiert werden müssen.<br />

– Viele Lader beinhalten gleichzeitig Binde-Funktion. Binde/Lader sind<br />

heutzutage typische Komponenten in Rechensystemen. Binde/Lader sind<br />

Bestandteil der Dienste, die ein Betriebssystem anbietet.<br />

£ Binde/Lader: Programmmodule werden zur Ladezeit gebunden.<br />

£ Lauf 1: Zuweisung von Adressen zu externen Referenzen (Auflösen von<br />

Referenzen)<br />

£ Lauf 2: Binden, Verschieben, Laden<br />

– Absoluter Lader<br />

Aufgaben eines absoluten Laders; ein Lauf genügt.<br />

£ Prüfen des Header-Teils im Objekt-Programm, ob es sich um das dort<br />

spezifizierte Programm handelt und ob der für das Programm vorgesehene<br />

Speicher groß genug ist (Header-Infos über Programmgröße).<br />

£ Die Text-Einträge im Objekt-Programm werden gelesen und der Code<br />

wird an die dort angegebenen, absoluten Adressen des Speichers geladen.<br />

£ Beim Lesen des END-Eintrags springt der Lader zur angegebenen Start-<br />

Adresse des Programms, um die Programmausführung zu starten. Ein<br />

absoluter Lader hat jedoch eine Reihe von Problemen: a) Programmierer<br />

muss Lade-Adressen explizit angeben, b) Probleme bei Multiprogramming:<br />

Ladeadresse nicht vorab bekannt, c) Verschiebbarkeitsforderungen<br />

können nicht erfüllt werden, und d) Probleme bei Wiederverwendbarkeit<br />

von z.B. Bibliotheksfunktionen, wenn diese vorab vergebene absolute<br />

Adressen besitzen.<br />

– Relativer Lader<br />

Laden verschiebbarer Objekt-Programme, wobei die Information, welche<br />

Adressen neu zu berechnen sind, vom Assembler zur Verfügung<br />

gestellt werden, z.B. durch Modifikations-Einträge im Objekt-Programm.<br />

Modifikations-Einträge sind jedoch nicht für jede Maschinen-Architektur<br />

geeignet. Maschinen, die z.B. keine relative Adressierung kennen, erfordern,<br />

46


Schlichter, TU München 2.5. HARDWARENAHE PROGRAMME<br />

dass u.U. fast alle Adressen neu berechnet werden müssen durch den Lader.<br />

Entsprechend umfangreich sind dann die benötigten Modifikations-<br />

Einträge und entsprechend groß wird dann das Objekt-Programm. Die Verschiebbarkeit<br />

wird in Zusammenhang mit der Seitenadressierung (siehe<br />

Seite 168) detaillierter behandelt.<br />

Datenstrukturen eines Binde/Laders<br />

Der Binder benötigt eine Tabelle ESTAB ("external symbol table") für die<br />

aufzulösenden externen Referenzen, wenn im Programm externe Referenzen<br />

auftreten. Der Tabelleneintrag besteht aus [Symbol, Adresse]. ESTAB hat analoge<br />

Aufgaben wie die Symboltabelle des Assemblers. Der Tabelleneintrag beinhaltet<br />

u.U. auch den Modul, in dem das Symbol definiert ist.<br />

¯ Hilfsvariable<br />

– PADR: Startadresse im Speicher, wohin das gebundene Programm geladen<br />

werden soll. Der Wert wird i.d.R. durch das Betriebssystem ermittelt und<br />

dem Lader mitgeteilt.<br />

– CSADR: Startadresse des jeweils bearbeiteten Moduls; dieser Wert wird zu<br />

den Relativ-Adressen des jeweiligen Moduls hinzu addiert. CSADR steht für<br />

control section adr.<br />

¯ Algorithmus zum Lauf 1<br />

Festlegen der Startadresse PADR des zu ladenden Programms (also wohin es in<br />

den Speicher geladen werden soll). Jedes Modul wie folgt bearbeiten:<br />

– Header-Eintrag lesen und Eintrag in Symboltabelle ESTAB:<br />

[Name des Moduls, Startadr. (=CSADR) des Moduls].<br />

Beim ersten Modul gilt: PADR=CSADR.<br />

– Lesen von Export-Einträgen (Symbol-Definitionen) im Objekt-Programm;<br />

alle auftretenden Symbole in ESTAB eintragen, wobei gilt:<br />

[symbolischer-Name, Adresse = Relativadr + CSADR].<br />

– Lesen des END-Eintrags: CSADR = CSADR_alt + Länge des Segments<br />

(steht als Info im Header); Bearbeiten des nächsten Moduls mit der neuen<br />

Anfangsadresse CSADR.<br />

¯ Algorithmus zum Lauf 2<br />

47


Schlichter, TU München 2.5. HARDWARENAHE PROGRAMME<br />

Nach Lauf 1 enthält ESTAB alle externen Symbole, die in Modulen definiert<br />

wurden zusammen mit deren Adresse. Der 2. Lauf erledigt die Funktionen<br />

Laden, Verschieben, Binden.<br />

– Sukzessives Lesen der Text-Einträge aus Objektprogramm; Abspeichern des<br />

Codes an "Startadresse des Segments + Relativadresse" im Eintrag. Die<br />

Startadresse des Segments ist CSADR und ist jeweils im Eintrag zum Modul<br />

in ESTAB enthalten.<br />

– Wird ein Modifikations-Eintrag gelesen, so wird das extern referenzierte<br />

Symbol bzw. dessen Adresse, in ESTAB nachgeschlagen.<br />

– Ist das letzte Modul bearbeitet und dessen END-Eintrag gelesen, so wird<br />

zum dort angegebenen Beginn des Programms gesprungen und die Kontrolle<br />

zur Ausführung des Programms wird an das Programm abgegeben. Bei<br />

mehreren Objektprogrammmodulen enthält meist nur das Hauptprogramm<br />

eine Angabe einer Startadresse. Falls kein Modul eine Startadresse definiert,<br />

wird vom Lader per default die Anfangsadresse PADR genommen. Damit<br />

gilt folgendes: Reihenfolge, in der Module geladen werden spielt keine<br />

Rolle. Andere Möglichkeit: Startadresse des geladenen Programms wird an<br />

das Betriebssystem zurückgeliefert und Benutzer muss mit einem Execute-<br />

Befehle (exec) explizit die Ausführung starten.<br />

Dynamisches Binden<br />

Binden von Unterprogrammen erst zur Laufzeit, d.h. erst wenn sie das erste Mal<br />

aufgerufen werden. Als Vorteile ergeben sich folgende:<br />

¯ Nach Bedarf laden<br />

Unterprogramme werden also nur dann, wenn sie tatsächlich gebraucht werden,<br />

zum in Ausführung befindlichen Programm hinzu gebunden. Bei großen<br />

Unterprogrammen oder bei Unterprogrammen mit vielen externen Referenzen<br />

kann man mit dynamischen Binden viel Speicherplatz und Zeit einsparen. Z.B.<br />

Nutzung einer großen Statistik-Bibliothek abhängig von Eingabewerten, die<br />

erst zur Laufzeit bekannt sind: kein Binden einer vollständigen Kopie der<br />

Bibliothek nötig.<br />

Beispiel Windows: Routinen in Dynamic Link Libraries (DLL) zusammengefasst;<br />

erst wenn sie benötigt wird, Laden der gesamten DLL.<br />

¯ Code-Sharing<br />

Dynamisches Binden wird oft verwendet, wenn mehrere ausführfähige<br />

Programme eine einzige Kopie eines Unterprogramms oder einer Bibliothek<br />

48


Schlichter, TU München 2.6. HARDWARENAHE DATENSTRUKTUREN<br />

gemeinsam nutzen sollen. Z.B. werden für die Programmiersprache C<br />

die Routinen für die Laufzeit-Unterstützung in der dynamic link library<br />

zusammengefasst. Es wird dann nur eine Kopie der Routinen der Bibliothek<br />

in den Arbeitsspeicher geladen und alle ausführenden Programme können dann<br />

dynamisch diese Kopie zu ihrem Programm hinzu binden, anstatt jeweils eine<br />

eigene Kopie in ihr Objektprogramm zu binden.<br />

2.6 Hardwarenahe Datenstrukturen<br />

Dieser Abschnitt behandelt kurz einige hardwarenahe Datenstrukturen. Einige<br />

davon, z.B. Keller und Halde, wurden bereits zusammen mit ihren Operationen in<br />

der Informatik-Einführungsvorlesung ausführlich vorgestellt.<br />

2.6.1 Felder<br />

Eindimensionale Felder<br />

Angenommen wir haben ein Feld a[u:o] von Elementen mit u o; u ist die untere<br />

Grenze und o die obere Grenze des Feldes. In Java ist die untere Grenze immer<br />

0, d.h. ein Feld beginnt immer mit dem Feldelement a[0]. Es gibt jedoch andere<br />

Programmiersprachen, bei denen der Programmierer sowohl die untere als auch<br />

die obere Feldgrenze frei wählen kann, jedoch mit u o. Es ergibt sich folgende<br />

Möglichkeit einer linearen Anordnung im Speicher.<br />

a[u]<br />

a[u+1]<br />

a[u+2]<br />

a[o-1]<br />

a[o]<br />

49


Schlichter, TU München 2.6. HARDWARENAHE DATENSTRUKTUREN<br />

Die Anzahl der benötigten Bytes pro Feldelement ergibt sich durch die Art der<br />

Feldelemente, z.B. bei integer wird Kennung W verwendet mit LOP = 4 Bytes.<br />

¯ Zugriff auf Feldelement<br />

Das Element a[j] (mit u j o) soll in das Register R0 gebracht werden. Die<br />

Adresse des ersten Elementes a[u] sei die symbolische Adresse a. Der Index j<br />

stehe im Register R2. Das Register R2 darf verändert werden. Die Untergrenze<br />

u steht in Register R3.<br />

– LOP ist die Länge in Bytes eines Feldelements; adr(a[u]) liefert die Adresse<br />

des Feldelements a[u].<br />

Ö ℄ Ö Ù℄ Ù ÄÇÈ<br />

– Im Assemblercode der MI<br />

ÅÇÎ Ê Ö×× ÚÓÒ Ù℄<br />

ËÍ Ï Ê Ê Ê Ê Ê Ù<br />

ÅÇÎ Ï Ê Ê Ê<br />

Die Adressrechnung ist folgendermaßen: inhalt(R1) + (j-u)*4, da die<br />

Kennung W verwendet wird. Zur Adressierung wird also das Inkrement (j<br />

- u) benötigt. Nachteil, da das Inkrement (j - u) jeweils berechnet werden<br />

muss. Dieser Nachteil lässt sich durch Einführung der sogenannten fiktiven<br />

Anfangsadresse adr(a[0]) vermeiden.<br />

¯ Fiktive Anfangsadresse<br />

Ö ℄ Ö Ù℄ Ù ÄÇÈ ÄÇÈ<br />

Ö ℄ ÄÇÈ<br />

adr(a[0]) ist die fiktive Anfangsadresse des Feldes a. Die fiktive Anfangsadresse<br />

muss im Speicher abgelegt werden. I.a. wird sie unmittelbar vor dem<br />

Feldelement a[u] abgelegt.<br />

– Im Assemblercode der MI<br />

ÅÇÎ Ê<br />

ÅÇÎ Ï Ê Ê Ê<br />

Die symbolische Adresse a zeigt auf das 1. Feldelement a[u]. Die fiktive<br />

Anfangsadresse a[0] wird unmittelbar vor a[u] gespeichert; deshalb muss -4<br />

abgezogen werden. Probleme mit obigem Programmstück:<br />

a) die Indexgrenzen werden nicht überprüft,<br />

b) es wird nicht überprüft, ob der Zugriff im Speicherbereich der Reihung<br />

bleibt.<br />

50


Schlichter, TU München 2.6. HARDWARENAHE DATENSTRUKTUREN<br />

Bei eindimensionalen Reihungen sind diese beiden Prüfungen äquivalent.<br />

Bei mehrdimensionalen Feldern ist die erste genannte Prüfung die schärfere.<br />

Wir ordnen daher jeder Reihung einen unabhängig abgespeicherten<br />

Felddeskriptor zu, der auch Informationen über Dimension und Feldgrenzen<br />

enthält.<br />

Mehrdimensionale Felder<br />

Angenommen wir haben ein Feld a[u1:o1,..., uk:ok] von Elementen mit uj oj;<br />

uj ist die untere Grenze und oj die obere Grenze der j-ten Dimension des Feldes.<br />

¯ Linearisierung<br />

des Feldes im Arbeitsspeicher, so dass der letzte Index am schnellsten läuft.<br />

Beispielsweise werden bei einem 3-dimensionalen Feld die Feldelemente in der<br />

Reihe a[u1,u2,u3], a[u1,u2,u3+1], a[u1,u2,u3+2],...a[u1,u2,o3], a[u1,u2+1,u3],<br />

a[u1,u2+1,u3+1], ..., a[u1+1,u2,u3], ....a[o1,o2,o3]. Eine andere Möglichkeit<br />

ist es den ersten Index am schnellsten laufen zu lassen.<br />

¯ Vorschrift zur Adressberechnung<br />

Ö ℄ <br />

Ö Ù Ù℄<br />

Ù × Ù × Ù<br />

ÄÇÈ<br />

mit den Spannen sj = oj - uj + 1. Herausziehen der konstanten Terme und<br />

Nutzung der fiktiven Anfangsadresse:<br />

Ö ℄ <br />

Ö ℄<br />

× × ÄÇÈ<br />

Ö ℄ <br />

Ö Ù Ù℄<br />

Ù × Ù × Ù ÄÇÈ<br />

Problematisch bei der zweiten Art der Adressrechnung ist, dass die fiktive<br />

Adresse adr(a[0, ..., 0]) negativ werden kann und der Wert möglicherweise<br />

auch nicht mehr in einem Wort darstellbar ist. Dieser Fall tritt insbesondere<br />

bei sehr hohen unteren Indexgrenzen auf. Für solche Fälle ist es also besser,<br />

das erstgenannte Berechnungsschema mit den Differenzen zwischen aktuellem<br />

Index und unterer Grenze zu verwenden. Zur Kontrolle auf Indexfehler kann<br />

für jeden Index überprüft werden, ob i u und i-u s ist, wobei u die untere<br />

Grenze und s die zugehörige Spanne ist.<br />

51


Schlichter, TU München 2.6. HARDWARENAHE DATENSTRUKTUREN<br />

¯ Felddeskriptor<br />

Prinzipiell ist folgende Information in einem Felddeskriptor enthalten:<br />

– Die Anzahl der Indexpositionen (Dimension) des Feldes.<br />

– die Konstanten zur Berechnung der Adresse, z.B. die Indexgrenzen bzw. die<br />

Spannen, aber auch LOP (Komponentenlänge).<br />

– die Werte, die für die vorgesehenen Kontrollen vorgesehen sind, beispielsweise<br />

zur Überprüfung der Indexgrenzen.<br />

– die Kennung der Daten oder ähnliche Angaben, damit ein einheitlicher<br />

Zugriffsalgorithmus für alle Felder realisiert werden kann.<br />

steigende<br />

Adressen<br />

adr (a[0,...,0])<br />

k<br />

u1<br />

sk<br />

LOP<br />

Gestreute Realisierung von Felder<br />

a:<br />

fiktive Anfangsadresse<br />

Dimensionenanzahl<br />

Anfangsindex der 1. Dim.<br />

s1 Spanne der 1. Dim.<br />

Spanne der k-ten Dim.<br />

Komponentenlänge<br />

a Anfangsadresse<br />

Im folgenden wird als Alternative zu linearisierten Realisierungen erklärt, wie 2dimensionale<br />

Felder (Matrix) gestreut realisiert werden können. Gestreut bedeutet<br />

dabei, dass ein Feld statt mit einem linearen Speicherbereich mit mehreren<br />

linearen Speicherbereichen, die im Arbeitsspeicher gestreut sein können, realisiert<br />

wird. Dabei kann das 2-dimensionale Feld entweder zeilenweise oder<br />

spaltenweise im Arbeitsspeicher abgelegt werden.<br />

¯ Sei a[u1:o1, u2:o2] das darzustellende Feld;<br />

52


Schlichter, TU München 2.6. HARDWARENAHE DATENSTRUKTUREN<br />

a[u1, *]<br />

a[o1, *]<br />

ref(u1) ref(o1) Referenzen<br />

1. Zeile von a<br />

letzte Zeile von a<br />

Der Speicherbereich Referenzen beinhaltet die Verweise auf die jeweiligen<br />

Zeilen des 2-dimensionalen Feldes, die als linearer Speicherbereich verwaltet<br />

werden.<br />

2.6.2 Programme im Arbeitsspeicher<br />

Der Adressraum eines Programmes besteht aus drei Teilen: dem statischen Bereich<br />

mit seinen Maschinenbefehlen und statischen Variablen, der Halde für die dynamischen<br />

erzeugten Datenstrukturen und dem Keller, der die Blockschachtelung<br />

der Ablaufstruktur bzgl. der Methodenaufrufe (Unterprogrammaufrufe) widerspiegelt.<br />

Keller/Stapel<br />

Halde<br />

Maschinenbefehle<br />

statische Variable<br />

steigende<br />

Adressen<br />

¯ Der Keller/Stapel dient zur Aufnahme der Daten bei dynamischen Aktivierungen<br />

von Unterprogrammen (Methodenaufrufe); blockorientierte Speicherung.<br />

53


Schlichter, TU München 2.6. HARDWARENAHE DATENSTRUKTUREN<br />

¯ Die Halde dient zur Speicherung von Daten, die dynamisch zur Laufzeit<br />

aufgebaut werden, z.B. Listen.<br />

¯ Unterprogrammaufruf bei der MI<br />

Deklaration in einer Programmiersprache<br />

ÔÙÐ ÒØ ÔÖÓ ÒØ Ô ÒØ ÔÒ ß<br />

<br />

Aufruf im Hauptprogramm: Ö×ÙÐØ ÔÖÓ Ú ÚÒ<br />

– Ablage im Keller<br />

R12<br />

R13<br />

SP<br />

......<br />

Rückgabewert<br />

vn<br />

......<br />

v1<br />

PC<br />

R14<br />

......<br />

R0<br />

lokale Variable<br />

freier Keller<br />

Keller<br />

wachstum<br />

steigende<br />

Adressen<br />

– Die Parameter stehen im Keller. Der letzte Parameter wird als erster<br />

in den Keller geschrieben. Unmittelbar vor Aufruf des Unterprogramms<br />

zeigt der Kellerpegel auf den ersten Parameter. Achtung: Bei Aufruf<br />

des Unterprogramms wird noch die Rückkehradresse im Keller abgelegt.<br />

Im Keller wird auch Speicherplatz für das Ergebnis des Unterprogramms<br />

reserviert. Falls das Ergebnis sehr groß ist bzw. die Größe nicht a priori<br />

bekannt ist. wird nur Speicherplatz für eine Adresse reserviert. Das Ergebnis<br />

54


Schlichter, TU München 2.6. HARDWARENAHE DATENSTRUKTUREN<br />

wird dann auf der Halde gespeichert, und das Unterprogramm gibt nur eine<br />

Adresse auf die Datenstruktur in der Halde zurück.<br />

– Unmittelbar nach dem Aufruf werden die aktuellen Register gesichert.<br />

– Die lokalen Variablen werden ebenfalls im Keller abgelegt. Wir nennen<br />

diesen Bereich den lokalen Datenraum.<br />

– R14 (SP) ist immer der aktuelle Kellerpegel. Im Gegensatz zu R12 und R13<br />

verändert sich also SP normalerweise dynamisch in der Prozedur.<br />

– Die Register R12 und R13 werden in Unterprogrammen wie folgt benutzt:<br />

£ R12 zeigt im Keller auf den Bereich der Parameter. Es enthält die<br />

Ablageadresse des ersten Parameter.<br />

£ R13 enthält die Basisadresse für den lokalen Datenraum,<br />

– Befehlsfolge in MI Assembler<br />

Hauptprogramm:<br />

ÔÙ× Ê ÛÖØ ÎÓÖÖØÙÒ×Ô×<br />

ÔÙ× ÚÒ<br />

ÔÙ× Ú<br />

ÄÄ ÔÖÓ<br />

ÔÓÔ ÐÐ ÈÖÑØÖ<br />

Ò× ÐÐ Ò<br />

Ê ÛÖØ<br />

Unterprogramm proc:<br />

Æ ÖØÙÒ×Ô×<br />

55


Schlichter, TU München 2.6. HARDWARENAHE DATENSTRUKTUREN<br />

ÈÍËÀÊ ÒÒ×Ô× Ë ÖÒ Ö<br />

Ê×ØÖ Ê×ØÖ<br />

ÛÖÒ Ö×Ø ÚÓÒ Ö ÙÖÙÒÒ<br />

ÈÖÓÞÙÖ × ÖØ ÙÒ ÞÛÖ<br />

ÚÓÖ ÔÖÓ Ê×ØÖ ÚÖÒÖØ<br />

ÙÖ È<br />

ÅÇÎ ËÈ Ê Ö×× Ö×ØÖ ÈÖÑØÖ Ò <br />

Ê Ê×ØÖ ÝØ× ÖØ<br />

ÝØ× ×ÔÐ ÑÒØ<br />

ÅÇÎ Ï ËÈ Ê ××Ö×× ÐÓÐÖ ØÒÖÙÑ<br />

Ò Ê <br />

ÐÓÐÒ ØÒÖÙÑ ÒÐÒ<br />

Ö ÒÙÒ×Ô×<br />

ÅÇÎ Ï Ê ËÈ × ÐÙ××Ô× ××Ö××<br />

ÐÓÐÖ ØÒÖÙÑ Ò ËÈ ÐÐ×<br />

ÃÐÐÖ Ò Ø ÖØ× ÚÐÐ ÙÖ <br />

ÈÖÓÞÙÖ ÙØ ÛÙÖ<br />

ÙÖ ÛÖ Ö ÐÓÐ ØÒÖÙÑ<br />

ÑÔÐÞØ Ð× Ø<br />

ÈÇÈÊ Ê×ØÙÖÖÒ Ê×ØÖ<br />

ÊÌ Ê Ö<br />

¯ Haldenverwaltung<br />

In Informatik-Einführungsvorlesung wurde bereits gezeigt, wie dynamisch<br />

erzeugte Daten, z.B. Listen und Objekte auf der Halde gespeichert werden. Die<br />

Halde wird nicht nach dem Kellerprinzip verwaltet. Zellen des Kellerspeichers<br />

werden mit Hilfe der Operation pop oder durch Zurücksetzen des Kellerpegels<br />

in Register SP (R14) freigegeben. Kellerbereiche werden nach dem LIFO-<br />

Prinzip verwaltet. Datenobjekte der Halde werden bei Bedarf erzeugt und<br />

gelöscht. Nicht mehr benötigte Datenobjekte werden entweder explizit<br />

durch einen Programmaufruf entfernt (z.B. durch Anweisung free(objref))<br />

oder implizit durch das System mit Hilfe der Speicherbereinigung (garbage<br />

collection). Garbage collection ist eine Komponente des Laufzeitsystems, das<br />

nicht referenzierte Objekte identifiziert, und deren Speicherplatz auf der Halde<br />

freigibt.<br />

– Der Speicherbereich einer Halde besteht aus zwei Klassen:<br />

£ Belegtbereiche: Speicherbereiche werden für Realisierungen von<br />

Datenobjekten verwendet.<br />

£ Freibereiche: Speicherbereiche, die momentan nicht für Realisierungen<br />

von Datenobjekten verwendet werden; d.h. sie sind frei. Belegt-<br />

56


Schlichter, TU München 2.6. HARDWARENAHE DATENSTRUKTUREN<br />

/Freibereiche sind nicht konsekutiv im Arbeitsspeicher organisiert,<br />

sondern bestehen jeweils aus einer Menge von Teilbereichen.<br />

– Buchführung des Speicherbereichs einer Halde mit Hilfe von Belegungs- und<br />

Freigabeoperationen.<br />

– Freiliste<br />

Die Freibereiche der Halde werden mit Hilfe einer Liste (z.B. einfach<br />

verkettet) verwaltet.<br />

ÔÙÐ Ð×× ÖÖ ß<br />

ÒØ ×Þ<br />

ÖÖ ÒÜØ<br />

ÑØÓÒÒØÓÒÒ<br />

<br />

Für jeden verfügbaren Freibereich wird jeweils die Größe in Bytes<br />

gespeichert.<br />

£ Auswahl eines geeigneten Freibereichs<br />

Bei Erzeugung eines neuen Datenobjektes wird die Operation<br />

Ð ÒØ ×Þ ausgeführt. Der Parameter size spezifiziert hier die<br />

Größe des benötigten Speicherbereichs auf der Halde. Für die Auswahl<br />

eines geeigneten Freibereichs zur Erfüllung der gestellten Anforderungen<br />

existieren verschiedene Verfahren.<br />

Æ first-fit-Verfahren<br />

bestimme von Beginn der Freiliste den ersten Speicherbereich, der<br />

die Anforderung erfüllt. Der gefundene freie Speicherbereich wird<br />

aufgeteilt in den Belegtbereich und den nicht benötigten Bereich.<br />

Letzterer wird wieder in die Freiliste eingetragen. Es kann passieren,<br />

dass am Beginn der Freiliste die Freibereiche immer kleiner werden,<br />

d.h. nachfolgende Anforderungen müssen mehr Elemente in der<br />

Freiliste untersuchen.<br />

Æ next-fit-Verfahren<br />

bestimme in der Freiliste den ersten Speicherbereich, der die Anforderung<br />

erfüllt. Die Suche wird dort fortgesetzt, wo die letzte Suche<br />

beendet wurde.<br />

Æ best-fit-Verfahren<br />

bestimmt in der gesamten Freiliste den Speicherbereich, der am<br />

besten die gestellte Anforderung erfüllt, d.h. mit möglichst wenig<br />

Verschnitt. best-fit ist langsamer als first-fit und next-fit, da jeweils<br />

die gesamte Freiliste durchsucht werden muss. Überraschenderweise<br />

führt es im Durchschnitt zu größerer Speicherverschwendung; das<br />

Zuteilungsverfahren hinterläßt mehr sehr kleine Speicherbereiche, die<br />

nicht mehr zugeteilt werden können.<br />

57


Schlichter, TU München 2.6. HARDWARENAHE DATENSTRUKTUREN<br />

Æ worst-fit-Verfahren<br />

bestimme in der Freiliste den größten freien Speicherbereich und teile<br />

ihn in einen Belegtbereich (zur Erfüllung der Anforderung) und einen<br />

verbleibenden Freibereich auf. Mit Hilfe des worst-fit-Verfahrens soll<br />

die Problematik des best-fit-Verfahrens mit seinen vielen kleinen, meist<br />

nicht mehr nutzbaren freien Speicherbereichen vermieden werden.<br />

£ Fragmentierung<br />

Problematisch ist die Entstehung von vielen kleinen freien Rest-<br />

Freibereichen, die wegen ihrer kleinen Längen als Belegtbereiche<br />

ungeeignet sind. Zur Vermeidung dieser nutzlosen, kleinen Freibereiche<br />

ist es zweckmäßig, eine Minimallänge für Freibereiche festzulegen<br />

und bei Belegungsanforderungen entsprechend längere Belegtbereiche zu<br />

erzeugen. Auch wird mit Hilfe des worst-fit-Verfahrens die Problematik<br />

etwas reduziert.<br />

Animation Haldenverwaltung<br />

siehe online Version<br />

58


Kapitel 3<br />

Parallele Systeme<br />

Bis jetzt haben wir die Modellmaschine MI als eine Ein-Benutzer, Ein-<br />

Programm Rechenanlage betrachtet ohne ein Betriebssystem, das die Ausführung<br />

von Programmen koordiniert. Wir haben uns dabei mit der Formulierung<br />

von Benutzerprogrammen auf maschinennaher Ebene beschäftigt. Für die<br />

Ausführung von Programmen sind eine Reihe von organisatorischen Maßnahmen<br />

notwendig. Die angesprochenen organisatorischen Aufgaben sind wesentlicher<br />

Bestandteil der Aufgaben eines Betriebssystems und die <strong>Programmierung</strong> eines<br />

Betriebssystems gehört zu dem Bereich der systemnahen <strong>Programmierung</strong>.<br />

Typischerweise finden in einem allgemeinen Rechensystem eine Vielzahl<br />

paralleler Abläufe statt, die miteinander koordiniert werden müssen. Bevor<br />

wir auf die Aufgaben eines Betriebssystems und insbesondere auf die Bereiche<br />

Prozess- und Prozessorverwaltung, Speicherverwaltung sowie Ein/Ausgabe<br />

eingehen, werden wir uns zunächst mit den Problemen beschäftigen, die sich<br />

daraus ergeben, dass in einem Rechensystem eine Vielzahl von parallelen<br />

Abläufen/Prozessen, existieren kann, die sich beeinflussen können, miteinander<br />

kommunizieren oder auch in Konkurrenz zueinander stehen können.<br />

3.1 Fragestellungen<br />

¯ Bisher betrachtete Aspekte von systemnaher <strong>Programmierung</strong>:<br />

– Programm als Repräsentation eines Algorithmus; ein Algorithmus ist ein<br />

schrittweise effektiv durchführbares Verfahren, in endlichen Schritten; er hat<br />

eine endliche eindeutige Beschreibung.<br />

– Programm als sequentielle Folge von Aktionen/Anweisungen (alle Schritte<br />

nacheinander);<br />

59


Schlichter, TU München 3.2. GRUNDLAGEN<br />

– determinierte Programme: unter gleichen Bedingungen und Eingaben<br />

produziert das Programm stets das gleiche Ergebnis; dies erlaubt eine<br />

einfaches Testen bzw. Debuggen der Programme und der Prozessabläufe.<br />

– deterministische Abläufe: eindeutig vorbestimmter Ablauf, keine willkürliche<br />

Auswahl von alternativen Schritten.<br />

¯ Übergang<br />

von sequentiellen Systemen hin zu parallelen Systemen/Programmen. Dabei<br />

werden die folgenden Aspekte näher betrachtet.<br />

– gleichzeitige Aktivität von Komponenten, die möglicherweise miteinander<br />

kommunizieren oder aufeinander einwirken.<br />

– Beispiele<br />

£ HW-Komponenten eines Rechensystems, z.B. Prozessor und E/A-<br />

Controller, siehe Rechnerarchitektur (siehe Seite 14).<br />

£ SW-Komponenten eines Rechensystems, z.B. parallel ablaufende Programme,<br />

siehe MI-Mehrprozessorarchitektur (siehe Seite 19); u.U. Zugriff<br />

auf gemeinsame Ressourcen, z.B. Daten im Arbeitsspeicher.<br />

£ SW-Komponenten in einem verteilten System, d.h. Rechensysteme, die<br />

über ein Rechnernetz miteinander verbunden sind.<br />

– Aspekte des Abschnitts<br />

£ Modellierungstechniken zur Analyse und Beschreibung der Eigenschaften<br />

paralleler Systeme (Spuren, Petrinetze).<br />

£ Threads als Mittel zur Realisierung von Parallelität innerhalb eines<br />

Prozesses.<br />

£ Synchronisation in parallelen Systemen. Hier geht es darum, dass<br />

Konkurrenz in parallelen Systemen koordiniert werden muss, um<br />

Inkonsistenzen in Rechensystemen zu vermeiden. Erhaltung der kausalen<br />

Beziehungen zwischen Aktionen; Synchronisation des Zugriffs auf<br />

gemeinsame Ressourcen.<br />

£ Mechanismen zur Behandlung von Verklemmungen. Im Rechensystem<br />

gibt es keinen Fortschritt, da sich die einzelnen Prozesse gegenseitig<br />

blockieren.<br />

3.2 Grundlagen<br />

In diesem Teilabschnitt werden kurz die wichtigsten Begriffe definiert sowie<br />

Konzepte zur Formulierung paralleler Aktivitäten aufgelistet. Einige dieser<br />

Konzepte werden in nachfolgenden Teilabschnitten ausführlicher diskutiert.<br />

60


Schlichter, TU München 3.2. GRUNDLAGEN<br />

3.2.1 Begriffsdefinitionen<br />

Nebenläufigkeit<br />

Nebenläufigkeit (engl. concurrency) bezieht sich auf die zeitliche Beziehung<br />

zwischen den Aktivitäten von Komponenten, die gleichzeitig oder zeitlich<br />

verzahnt (engl. interleaving) ablaufen können.<br />

¯ z.B. gleichzeitig: Drucken eines Dokuments und Berechnen einer Formel in<br />

einer Tabellenkalkulation (CPU-Nutzung).<br />

¯ z.B. zeitlich verzahnt: Benutzerauftrag muss CPU abgeben und wartet; ein<br />

anderer Auftrag wird (teilweise) ausgeführt und gibt CPU wieder zurück bevor<br />

das Ende erreicht ist. Hier spricht man auch von Pseudoparallalität.<br />

Parallelität<br />

Parallelität wird häufig synonym zu Nebenläufigkeit verwendet;<br />

¯ spezielle Form der Nebenläufigkeit: mehrere Prozessoren stehen zur Ausführung<br />

zur Verfügung. Ein Beispiel dafür ist die MI Modellmaschine mit bis<br />

zu 4 Prozessoren. Auch bei einem Ein-Prozessor gibt es echte Parallelität zwischen<br />

E/A-Controller (z.B. mit angeschlossenem Drucker) und CPU.<br />

Verteiltheit<br />

Verteilheit (engl. distribution) ist die räumliche oder auch nur konzeptionelle<br />

Aufteilung der Komponenten eines Systems, z.B. vernetzte PCs. Die Verteilung<br />

kann sich sowohl auf der Ebene der HW-Komponenten als auch auf der Datenund<br />

Anwendungsebene abspielen. Der Verteilungsaspekt wird vor allem Ende der<br />

Vorlesung näher beleuchtet.<br />

Interaktion<br />

Kommunikation, Synchronisation, Konkurrenz betrifft die kausalen Beziehungen<br />

zwischen räumlich verteilten und nebenläufig ausgeführten Aktivitäten.<br />

¯ kausale Abhängigkeit zwischen Ampel und Fußgänger:<br />

Ereignis von Fußgänger:<br />

er drückt Knopf<br />

Ereignis beeinflusst Ampel: sie schaltet auf Rot für Auto<br />

61


Schlichter, TU München 3.2. GRUNDLAGEN<br />

¯ Kommunikation: Prozesse auf dem gleichen oder unterschiedlichen Rechensystemen<br />

tauschen Nachrichten untereinander aus.<br />

¯ Koordinierung: Beziehung zwischen Auftraggeber und Auftragnehmer<br />

Erstellen eines Auftrages durch Client und anschließendes Bearbeiten des<br />

Auftrags durch Server.<br />

¯ Konkurrenz: Aktivitäten eines Prozesses behindern die eines anderen Prozesses<br />

z.B. Warten, wenn CPU von anderem Prozess belegt.<br />

Nichtdeterminismus<br />

System zeigt bei gleichen Ausgangsbedingungen und gleichen Eingaben<br />

unterschiedliches Verhalten (Reihenfolge der Prozesse spielt eine Rolle!).<br />

Problem: Nichtreproduzierbarkeit von Ergebnissen, Testen von parallelen<br />

Programmen bei Nichtdeterminismus ist schwierig. Beispiel:<br />

Ü ÈÖÓÞ×× Ü Ü ÈÖÓÞ×× Ü Ü<br />

Ausführungsreihenfolge<br />

È ÚÓÖ È Ü <br />

È ÚÓÖ È Ü <br />

3.2.2 Beschreibungskonzepte<br />

Es gibt eine Vielzahl von Konzepten zur Formulierung paralleler Aktivitäten.<br />

In der Vorlesung werden wir uns vor allem mit den beiden modell-basierten<br />

Ansätzen, Ereignisse und Petrinetze befassen. Es gibt auch noch andere<br />

Modellansätze, z.B. formale Beschreibungssprachen (Estelle, LOTOS), die<br />

z.T. auf Prozessalgebren basieren. Eine andere Möglichkeit sind parallele<br />

Programmiersprachen.<br />

modell-basierte Konzepte<br />

¯ ereignis-orientiert: es wird der Ablauf von Prozessen betrachtet; jeder<br />

Ablauf wird durch eine Menge von Ereignissen charakterisiert. Jeder<br />

Ablauf repräsentiert eine Ereignisspur. Ereignisse können in kausalem<br />

Zusammenhang stehen. Es werden nun eine Menge von Prozessen und deren<br />

Zusammenwirken betrachtet, insbesondere auch wie deren Ereignismengen im<br />

Zusammenhang zueinanderstehen.<br />

62


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

¯ graphisch-orientiert: der Prozessablauf wird graphisch dargestellt. Petrinetze<br />

sind ein Beispiel dafür. Petrinetze sind Graphen mit 2 Arten von Knoten,<br />

den Stellen und Transitionen. Abläufe werden durch das Schalten von<br />

Transitionen und der Propagierung von Marken charakterisiert. Dabei können<br />

Aussagen bzgl. der kausalen Abhängigkeit, aber auch der Unabhängigkeit von<br />

Teilabläufen getroffen werden.<br />

Sprachkonstrukte in Programmiersprachen<br />

¯ parallele Komposition von Teilabläufen innerhalb eines Prozesses, z.B. Java<br />

Threads. Andere Beispiele sind Tasks in Ada, Prozesshierarchien in<br />

Betriebssystemen (fork, join) oder auch parbegin, parend.<br />

¯ Kommunikationskonzepte: u.a. send, receive<br />

¯ Synchronisationskonzepte: u.a. lock, unlock<br />

Konzepte in Betriebssystemen<br />

¯ Prozesskonzept = Programm in Ausführung;<br />

¯ Threadkonzept = leichtgewichtigter Prozess<br />

¯ Kommunikation: Shared memory, Dateien, Nachrichten etc.<br />

¯ Synchronisation: Unterbrechungen (Interrupts), Sperren etc. Das Auftreten<br />

von Unterbrechungen sowie deren Behandlung wird im Verlaufe der Vorlesung<br />

noch näher behandelt.<br />

3.3 Modellierung paralleler Systeme<br />

In diesem Abschnitt behandeln wir grundlegende Mechanismen zur Modellierung<br />

und Beschreibung parallel ablaufender Systeme. Siehe auch das Buch M. Broy<br />

"Informatik", Springer-Verlag. Insbesondere geht es in diesem Abschnitt um<br />

folgendes:<br />

das Verhalten von parallelen Systemen klären,<br />

sich auf wesentliche Aktionen, Ereignisse konzentrieren (Abstraktion),<br />

die Abhängigkeiten zwischen Aktionen ermitteln/klären,<br />

Fehler oder Konflikte aufgrund paralleler Tätigkeiten vermeiden und<br />

maximale Parallelität erzielen.<br />

63


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

3.3.1 Modellierungsziele<br />

Ziel ist die einfache Analyse und Beschreibung von parallelen Systemen.<br />

¯ Spezifikation eines Modells im Sinne von Abstraktion: Vereinfachung,<br />

Weglassen von Details, Beschränken auf interessierende Eigenschaften.<br />

¯ Beispiele interessanter Eigenschaften sind:<br />

– Determiniertheit.<br />

– Störungsfreiheit. Für störungsfreie Systeme gilt, dass unter Einhaltung der<br />

durch eine Ordnung (später wird hierzu die Kausalitätsordnung zwischen<br />

Ereignissen verwendet) festgelegten Reihenfolge, die Ausführungsreihenfolge<br />

der parallelen Ereignisse und deren Aktionen keinen Einfluss auf die<br />

berechneten Ergebnisse hat.<br />

– wechselseitiger Ausschluss. Hier geht es darum, dass bei konkurrierenden<br />

Zugriffen auf gemeinsame Ressourcen, die exklusiv benutzt werden, immer<br />

nur ein Prozess zu einem Zeitpunkt darauf zugreift. Damit soll die<br />

Konsistenz sichergestellt werden.<br />

– Endloses Blockieren (engl. Deadlock).<br />

– Verhungern (engl. Starvation). Beispielsweise erzielt ein Prozess keinen<br />

Fortschritt, da er nie rechnend gesetzt wird, obwohl er rechenbereit wäre.<br />

In Rechnerkernvergabe gibt es jedoch immer einen anderen rechenbereiten<br />

Prozess, der eine höhere Priorität hat.<br />

¯ Die Eigenschaften können in zwei Klassen eingeteilt werden.<br />

– Sicherheitseigenschaften (engl. safety): Sicherstellen, dass gewisse unerwünschte<br />

Zustände und unerwünschte Aktionsverläufe nicht auftreten; Formulierung<br />

durch Invarianten (z.B. wechselseitig ausgeschlossene Nutzung<br />

der CPU). Hier geht es nicht um Datensicherheit, d.h. persistente Speicherung<br />

von Daten, damit sie auch nach einem Systemcrash noch zur Verfügung<br />

stehen. Es geht auch nicht um Datenschutz, d.h. dass Daten nicht für<br />

andere Prozesse lesbar sind.<br />

– Lebendigkeitseigenschaften (engl. liveness): Garantieren, dass gewisse<br />

erwünschte Zustände bzw. Aktionsmuster in den Abläufen irgendwann<br />

auch auftreten (z.B. erwünschter Ablauf:<br />

irgendwann auch Fortschritte).<br />

rechenbereiter Prozess macht<br />

64


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

3.3.2 Verhaltensbeschreibung<br />

Verhaltensbeschreibungen eines dynamischen Systems sind Beschreibungen der<br />

Eigenschaften des Systems und deren Veränderungen über der Zeit. Das Verhalten<br />

eines Systems kann mit Spuren in einem 2-dimensionalen Raum beschrieben<br />

werden: Die 1. Dimension ist die Zeit, mit der das Fortschreiten der Ausführung<br />

der Berechnungen erfasst wird, d.h. hier geht es um die Folge von Ausführungen<br />

von elementaren Aktionen, die jeweils Ereignisse auslösen. Die 2. Dimension<br />

ist der Raum der Eigenschaften des Systems, mit dem die Systemzustände in<br />

Zeitpunkten erfasst werden. Zu Zeitpunkten wird jeweils ein Schnappschuss des<br />

Systemzustands genommen. Über die Zeitachse wird eine Folge von Zuständen<br />

angegeben, die sich mit der Ausführung der Aktionen (Berechnungen) ergibt.<br />

Verhaltensbeschreibung setzt sich aus den Basiseinheiten Aktionen und Zustände<br />

zusammen.<br />

¯ Eigenschaftenveränderungen sind Ausführungen von elementaren Aktionen.<br />

Ausführungen von komplexen Berechnungen können mit Kombinationen von<br />

Ausführungen dieser elementare Aktionen beschrieben werden. Es sind zwei<br />

Sichten möglich.<br />

– Die Sicht auf die Tätigkeiten, die auszuführen sind; in dieser Sicht sind<br />

die Basiseinheiten die atomaren Aktionen. Eine Aktion kann ein MI-<br />

Maschinenbefehl oder eine Java Anweisung sein.<br />

– Die Sicht auf die Veränderungen, die erfolgen und beobachtet werden<br />

können; in dieser Sicht sind die Basiseinheiten die atomaren Ereignisse,<br />

die eintreten. Die Ausführung einer Aktion führt zu einem Ereignis im<br />

Rechensystem. Aktionen und Ereignisse sind dual zueinander und können<br />

nach Bedarf genutzt werden; hier wird überwiegend die Ereignissicht<br />

benutzt. Aktionen können mehrfach ausgeführt werden; sie resultieren in<br />

mehrfachen Ereignissen.<br />

¯ Aktionen bzw. Ereignisse sind zeitlich geordnet. In einem sequentiellen<br />

System werden die elementaren Aktionen sequentiell ausgeführt, d.h. es<br />

existiert eine lineare Ordnung bzgl. der Zeitachse. Diese Zeitachse für<br />

Verhaltensbeschreibungen hat mit der gewohnten, physikalischen Zeit die<br />

lineare Ordnung gemeinsam; sie abstrahiert jedoch als diskrete Zeit von der<br />

Dauer der Ausführung von Aktionen. In einem parallelen System müssen<br />

zusätzlich auch nebenläufige Aktionen betrachtet werden, d.h. für sie kann<br />

keine zeitliche Reihenfolge bestimmt werden.<br />

¯ Zustände des Systems anhand der Werte der Datenobjekte. Folge von<br />

Zuständen gemäß der Zeitachse. Jedem Zeitpunkt wird der Zustand der<br />

65


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

Datenobjekte, der mit dem Zeitpunkt erreicht ist, zugeordnet. Für jeden<br />

Zeitpunkt wird damit ein Schnappschuss vom System angegeben; über der<br />

Zeitachse wird die Folge der Zustände angegeben, die sich mit der Ausführung<br />

der Berechnungen ergibt.<br />

¯ Spuren<br />

Es sind zwei Varianten von Verhaltensbeschreibungen zweckmässig.<br />

1. Ereignisspuren: Sie beschreiben den zeitlichen Ablauf der Berechnungen<br />

eines Systems mit Ereignissen, die linear geordnet sind.<br />

2. Zustandsspuren: Sie beschreiben den zeitlichen Ablauf der Berechnungen<br />

eines Systems anhand der auftretenden Zustände der Datenobjekte. Ereignisspur<br />

und Zustandsspur sind eng miteinander verknüpft. Bei Auftreten eines<br />

Ereignisse wird jeweils ein Schnappschuss des Systems genommen. Dieser<br />

Schnappschuss stellt ein Element der Zustandsspur dar.<br />

3.3.3 Ereignisse und Aktionsstrukturen<br />

In diesem Abschnitt wird der Begriff Prozess anhand von Aktionsstrukturen mathematisch<br />

gefasst. Dies ermöglicht die mathematische Modellierung beliebiger,<br />

nichtkontinuierlicher ("diskreter") Abläufe verteilter Systeme, insbesondere von<br />

Prozessen in Rechenanlagen. Durch diese Modellierung können jedoch auch andersartige,<br />

technische oder betriebliche Vorgänge, die sich aus Einzelaktionen<br />

zusammensetzen und zwischen denen kausale Beziehungen bestehen, erfasst werden.<br />

Prozess<br />

Gegeben seien eine Menge (das "Universum") E * von Ereignissen (engl. events)<br />

und eine Menge A von Aktionen (engl. actions).<br />

¯ Definition<br />

Ein Triple p = (E, , «) nennen wir einen Prozess oder auch eine<br />

Aktionsstruktur, falls folgende Aussagen gelten:<br />

– E E * , E heißt die Ereignismenge.<br />

– ist eine partielle Ordnung über E, ist die Kausalitätsrelation.<br />

Die partielle Ordnung ist eine reflexive, transitive und antisymmetrische<br />

Relation.<br />

66


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

– «: E A ist die Aktionsmarkierung des Prozesses p.<br />

– Die Abbildung « ordnet jedem Ereignis eine Aktion zu. In dieser Definition<br />

von Aktionsstrukturen ist auch der leere Prozess eingeschlossen. Er wird<br />

durch die Aktionsstruktur dargestellt, die aus der leeren Ereignismenge<br />

besteht.<br />

¯ Beispiel: Fußgängerübergang<br />

Wir betrachten einen Prozess mit 14 Ereignissen.<br />

Aktionen zugeordnet.<br />

Jedem Ereignis werden<br />

Ereignis Aktion<br />

e1 Knopf wird gedrückt<br />

e2 Ampel für Autofahrer schaltet auf Gelb<br />

e3 Ampel für Autofahrer schaltet auf Rot<br />

e4 Auto hält auf Spur 1<br />

e5 Ampel für Fußgänger schaltet auf Grün<br />

e6 Auto hält auf Spur 2<br />

e7 Fußgänger benutzt Fußgängerübergang<br />

e8 Auto hält auf Spur 3<br />

e9 Ampel für Fußgänger schaltet auf Rot<br />

e10 Ampel für Autofahrer schaltet auf Rot und Gelb<br />

e11 Ampel für Autofahrer schaltet auf Grün<br />

e12 Auto fährt an auf Spur 1<br />

e13 Auto fährt an auf Spur 2<br />

e14 Auto fährt an auf Spur 3<br />

e15 Knopf wird gedrückt<br />

Die Ausführung einer Aktion löst ein Ereignis aus. Wird dieselbe Aktion<br />

mehrmals ausgeführt, so wird jeweils ein neues Ereignis ausgelöst.<br />

– Die Relation der kausalen Abhängigkeiten sei gegeben durch:<br />

e1 e2, e2 e3, e3 e4, e3 e5, e3 e6, e5 e7,<br />

e3 e8, e5 e9, e9 e10, e10 e11, e11 e12,<br />

e11 e13, e11 e14, e4 e12, e6 e13, e8 e14, e9 e15.<br />

Die kausalen Abhängigkeiten ergeben keine vollständige Ordnung.<br />

– Diese Beziehungen erzeugen (durch die Bildung der reflexiv transitiven<br />

Hülle) eine partielle Ordnung, die die Kausalität zwischen den Ereignissen<br />

beschreibt. Man beachte, dass hier beispielsweise das Ereignis e12 nur<br />

stattfindet, nachdem die Ereignisse e4 und e11 stattgefunden haben.<br />

– Graphische Darstellung<br />

Endliche Prozesse lassen sich anschaulich durch knotenmarkierte, gerichtete,<br />

zyklenfreie Graphen darstellen, Die Knoten repräsentieren die Ereignisse<br />

und sind durch Aktionen markiert.<br />

67


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

e6<br />

e1 e2 e3 e4<br />

e8<br />

e5<br />

e9 e10 e11<br />

¯ Charakterisierung von Prozessen<br />

In einem Prozess hat jedes Ereignis eine eindeutige Identität ("X betritt am<br />

19.1.2001 um 11:15 h den Hörsaal"), eine Aktion kann jedoch mehrfach<br />

stattfinden (die Aktion "X betritt den Hörsaal" kann mehrfach stattfinden).<br />

Dementsprechend kann in einem Prozess verschiedenen Ereignissen die gleiche<br />

Aktion zugeordnet sein. Ereignisse haben einen eindeutigen Bezeichner;<br />

Prädikate sind eine andere Möglichkeit, Ereignisse zu identifizieren, z.B.<br />

Ermordung Kennedy's oder die Kreuzigung Christi.<br />

– Parallel, nebenläufig<br />

Für einen Prozess p = (E, , «) nennen wir zwei Ereignisse e1, e2 E<br />

parallel oder nebenläufig (engl. concurrent), falls sie im Prozess p nicht in<br />

einer kausalen Relation stehen, d.h. wenn gilt:<br />

(e1 e2 oder e2 e1)<br />

£ Parallele Ereignisse sind kausal unabhängig, sie können zeitlich<br />

nebeneinander oder in beliebiger Reihenfolge stattfinden.<br />

– Sequentiell<br />

Ein Prozess p = (E, , «) heißt sequentiell, wenn in ihm kein Paar von<br />

parallelen Ereignissen auftritt, d.h. die Kausalitätsrelation eine lineare<br />

Ordnung ist. Damit gilt für zwei beliebige Ereignisse e1 und e2 stets<br />

entweder e1 e2 oder e2 e1.<br />

– Der Ablauf eines Programmes kann auch als Prozess im Sinne der<br />

Aktionsstrukturen gedeutet werden.<br />

sequentielle Prozesse.<br />

– Endlich<br />

Sequentielle Programme erzeugen<br />

Ein Prozess p = (E, , «) heißt endlich, falls seine Ereignismenge<br />

eine endliche Menge ist. Beispielsweise ist das Abspielen einer CD ein<br />

endlicher Prozess, während ein Betriebssystem einen unendlichen Prozess<br />

68<br />

e7<br />

e15<br />

e14<br />

e13<br />

e12


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

repräsentiert. Unendliche Prozesse besitzen unendliche Ereignismengen.<br />

Unendliche Prozesse können jedoch endlich beschreibbar sein.<br />

Kausale Abhängigkeiten<br />

Häufig finden wir in Prozessen unterschiedliche Ursachen für die kausale<br />

Beziehung e d zwischen Ereignissen e und d. Im einzelnen können drei<br />

verschiedene Arten unterschieden werden.<br />

¯ Echt kausale Beziehungen<br />

das Ereignis e ist kausal für das Ereignis d in dem Sinn, dass d ohne e niemals<br />

auftreten kann.<br />

– Beispiel<br />

e = Geldeinwurf, d = Kartenausgabe; e d, d.h. der Fahrkartenautomat gibt<br />

erst dann eine Fahrkarte aus, wenn der passende Geldbetrag eingeworfen<br />

wurde.<br />

¯ zeitliche Beziehungen<br />

das Ereignis e endet, bevor das Ereignis d beginnt.<br />

– Beispiel: Nachricht muss gesendet sein, bevor sie empfangen werden kann.<br />

– Happend-before<br />

Die kausale Beziehung impliziert also eine zeitliche Relation; das ist die<br />

bekannte happened before-Beziehung von L. Lamport. Die Umkehrung<br />

gilt nicht. Die zeitliche Relation zwischen Ereignissen sagt nichts über die<br />

Kausalität aus.<br />

£ Wichtig: Ereignisse wurden als atomare Ereignisse modelliert. D.h.<br />

Beginn und Ende fallen auf einen Zeitpunkt zusammen. Ein alternativer<br />

Ansatz wäre die Spezifikation eines Zeitintervalls für ein Ereignis mit<br />

Anfangs- und Endzeitpunkt. Damit könnten auch Überlappungen von<br />

Ereignissen modelliert werden.<br />

£ Die Happend-before Relation spielt im Kontext von Verteilten Anwendungen<br />

eine wichtige Rolle (siehe Vorlesung Verteilte Anwendungen (URL:<br />

http://www11.in.tum.de/lehre/vorlesungen/archiv)). Insbesondere in der<br />

Gruppenkommunikation wird sie eingesetzt, um die an alle Gruppenmitglieder<br />

gesandten Nachrichten zu sequentialisieren. Auf diese Weise soll<br />

erreicht werden, dass alle Gruppenmitglieder in einen für die Gruppe konsistenten<br />

Zustand versetzt werden.<br />

69


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

¯ Systembeschränkungen<br />

Systembeschränkungen, z.B. wechselseitiger Ausschluss. Das Ereignis e darf<br />

nicht parallel zum Ereignis d auftreten.<br />

– Beispiel<br />

e = Fußgänger überquert die Fahrbahn beim Übergang, und<br />

d = Auto überfährt den Übergang.<br />

e und d dürfen nicht parallel ausgeführt werden, aber es besteht keine<br />

echte kausale Abhängigkeit zwischen e und d. Ereignisse, welche<br />

mit Aktionen markiert sind, die aufgrund von Systembeschränkungen<br />

nicht parallel stattfinden können, sind nicht unbedingt in einem "echt"<br />

kausalen Zusammenhang. Trotzdem sollten sie nicht als parallele<br />

Ereignisse auftreten. Um diese Systembeschränkungen mit den eingeführten<br />

Modellierungskonzepten (uninterpretierte Aktionen) zu erfassen, müssten sie<br />

in eine (künstliche) kausale Abhängigkeit gebracht werden; das ist aber meist<br />

nicht sehr sinnvoll. Wir werden später sinnvollere Möglichkeiten kennen<br />

lernen.<br />

Sequentialisierung<br />

Idee: vereinfachte Darstellung paralleler Abläufe, aus der Sicht eines<br />

Beobachters. Ein sequentieller Prozess hat genau eine vollständige Sequentialisierung,<br />

nämlich die vorgegebene Reihenfolge der Ereignisse. Durch « ergibt<br />

sich aus der Ereignisreihenfolge eine Folge von Aktionen. Vollständige Sequentialisierung:<br />

partielle Kausalitätsordnung zu linearer Ordnung ergänzen.<br />

¯ Definition<br />

Ein Prozess p 1 =(E 1 , 1 , « 1 ) heißt eine Sequentialisierung eines Prozesses p 2<br />

=(E 2 , 2 , « 2 ), falls gilt:<br />

E 1 =E 2<br />

e, d E 1 :e 2 d e 1 d<br />

« 1 = « 2<br />

– Ist p 1 sequentiell, so heißt die Sequentialisierung vollständig. Die<br />

Vervollständigung einer partiellen Ordnung zu einer linearen Ordnung heißt<br />

topologisches Sortieren.<br />

¯ Ein sequentieller Beobachter eines Prozesses ist ein Beobachter, der die<br />

Ereignisse eines Prozesses und die entsprechenden Aktionen in einem<br />

70


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

sequentiellen Ablaufprotokoll festhält. Parallele Aktionen werden dabei in<br />

eine zufällige Reihenfolge gebracht. Das Ergebnis der Beobachtung ist<br />

ein sequentieller Prozess, der einer zufällig gewählten Sequentialisierung<br />

entspricht. Gehen wir von sequentiellen Beobachtern aus, so erhalten wir<br />

sequentielle Prozesse als Beobachtungen.<br />

¯ Existiert für einen nichtsequentiellen Prozess eine Reihe von Beobachtungen,<br />

die alle vollständige Sequentialisierungen des Prozesses darstellen, so lässt sich<br />

aus diesen Beobachtungen der Prozess teilweise rekonstruieren. Kennen wir die<br />

Gesamtmenge aller Sequentialisierungen, so lässt sich der Prozess eindeutig<br />

rekonstruieren. Für den Beweis siehe Broy, Band II, S 12.<br />

¯ Die Ausführung eines Programms auf einer Rechenanlage kann ebenfalls<br />

als Prozess dargestellt werden. Gewisse Anweisungen ("Aktionen") eines<br />

Programms zerfallen bei der Ausführung auf einer Rechenanlage in eine Reihe<br />

von Einzelaktionen.<br />

¯ Beispiel<br />

Für das Beispiel des Fußgängerübergangs ist folgendes eine vollständige<br />

Sequentialisierung.<br />

e1 e2 e3 e4 e6 e5 e7 e8 e9 e10 e11 e14 e12 e13 e15<br />

¯ Spuren<br />

Darstellung sequentieller Prozesse mittels Spuren. Sequentielle Prozesse sind<br />

Spezialfälle paralleler Prozesse. Für die Darstellung sequentieller Prozesse<br />

bietet sich eine wesentlich einfachere Darstellungsform als Aktionsstrukturen.<br />

Wir können ganz auf die explizite Angabe von Ereignismengen verzichten und<br />

stattdessen endliche oder unendliche Sequenzen von Aktionen verwenden.<br />

– Sei A eine Menge von Aktionen, dann bezeichnen wir mit A + die Menge<br />

der endlichen Folgen von Aktionen aus A und mit A die Menge der<br />

unendlichen Folgen von Aktionen.<br />

– Jedem sequentiellen Prozess können wir eindeutig eine Folge von Aktionen<br />

zuordnen, wie sprechen von der Spur (engl. trace). Sei p = (E, , «) ein<br />

sequentieller Prozess. Wir definieren:<br />

£ spur : {p | p ist sequentieller Prozess } A + A<br />

£ spur(p) = empty, falls E = Ø<br />

£ spur(p) = a ¡ spur(p | E \ {e}), falls E Ø, wobei e das gemäß der<br />

Kausalitätsordnung kleinste Ereignis in p ist und «(e) = a gilt.<br />

71


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

p|E\{e}bezeichnet den Teilprozess, der durch die Einschränkung<br />

auf die Ereignismenge E \ {e} entsteht.<br />

"¡" ist hier die Konkatenation von Aktionen, die sich durch die Ereignisse<br />

ergeben. spur ist eine Abbildung auf die Menge der Aktionen. Als<br />

Ergebnis liefert spur einen Strom (engl. stream) von Aktionen.<br />

– Für einen nichtsequentiellen Prozess p gilt:<br />

Spuren(p) = {spur(q) : Prozess q ist eine vollständige Sequentialisierung<br />

von p}<br />

Spuren sind ein einfacheres Modell für sequentielle Abläufe eines Systems<br />

als Aktionsstrukturen. Da bei nichtsequentiellen Systemen in vielen<br />

Anwendungen die Frage, welche Aktionen parallel zueinander auftreten<br />

können, von untergeordneter Bedeutung ist, ist es naheliegend für<br />

solche Systeme vereinfachend statt ihrer nebenläufigen Prozesse deren<br />

Sequentialisierungen als Abläufe zu betrachten. In vielen Ansätzen zur<br />

Modellierung verteilter Systeme werden nicht Prozesse mit ihrer expliziten<br />

Darstellung von Parallelität, sondern die technisch etwas einfacher zu<br />

handhabenden Mengen von Aktionsströmen verwendet.<br />

3.3.4 Aktionen als Zustandsübergänge<br />

Neben der Beschreibung von Systemen durch die Prozesse, die deren Abläufe<br />

bilden, ist es naheliegend, Systeme durch Zustände und ihr Verhalten durch<br />

Zustandsänderungen zu modellieren. Zustandsraum = Menge aller<br />

Systemzustände. Dazu geben wir für ein System einen Zustandsraum an. Dieser<br />

besteht aus der Menge aller Zustände, die das System einnehmen kann. Auf dieser<br />

Basis beschreiben wir dann alle Zustandsübergänge, die im System auftreten<br />

können.<br />

Interpretierte Aktionen<br />

Aktionen werden Zustandsänderungen als Bedeutung zugeordnet. Bisher haben<br />

wir die Mengen der Aktionen nicht weiter interpretiert. Eine Deutung für<br />

Aktionen in Prozessen liefern Zustandsänderungen. Dazu weisen wir Aktionen<br />

Zustandsänderungen als Bedeutung zu. Dabei interessiert uns insbesondere die<br />

Frage, ob wir über diese Zuordnung auch Prozessen eindeutig eine Bedeutung<br />

zuordnen können.<br />

72


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

Modell<br />

Zu diesem Zweck definieren wir nichtdeterministische Zustandsautomaten mit<br />

Transitionsaktionen.<br />

¯ Zustandsautomat<br />

Ein nichtdeterministischer Zustandsautomat ist gegeben durch:<br />

– S, eine Menge von Zuständen, genannt Zustandsraum,<br />

– A, eine Menge von Transitionsaktionen,<br />

– R S ¢ A ¢ S eine Zustandsübergangsrelation,<br />

£ Seien s , s S und a A gegeben. (s , a, s ) R bedeutet,<br />

0 1<br />

0 1<br />

dass im Zustand s die Aktion a ausgeführt werden kann und dies zum<br />

0<br />

Nachfolgezustand s S führen kann.<br />

1<br />

£ Diese Art von Automaten heißt nichtdeterministisch, da in einem<br />

Zustand mehrere Transitionsaktionen möglich sein können und eine<br />

Transitionsaktion zu unterschiedlichen Nachfolgezuständen führen kann.<br />

£ Wir schreiben (für gegebene Relation R) s s , um auszudrücken, dass<br />

0 a 1<br />

(s ,a,s ) R gilt.<br />

0 1<br />

– S0 eine Menge von möglichen Anfangszuständen.<br />

¯ Beispiel Fahrkartenautomat<br />

Akzeptiert werden 1- und 2 DMark Münzen. Mittels zweier Knöpfe kann man<br />

zwischen einer Kurzstrecke für 1 DM oder einer normalen Fahrt für 2 DM<br />

wählen. Der Automat gibt Wechselgeld zurück.<br />

– Menge der Zustände<br />

S S xS mit<br />

1 2<br />

S = {Wahl, kurz, normal} und S = {-1,0,1,2}<br />

1 2<br />

mit der folgenden Interpretation eines Zustandes s = (a, b):<br />

a= Wahl: Automat wartet auf die Wahltaste<br />

a= kurz: eine Kurzstreckenkarte wurde gewählt und ist noch auszugeben<br />

a= normal: eine normale Fahrkarte wurde gewählt und ist noch<br />

auszugeben<br />

b= -1 : es ist noch 1 DM zurückzugeben<br />

b= 0 : es ist kein Geld mehr einzuwerfen oder zurückzugeben<br />

b= 1 : es muss noch 1 DM eingeworfen werden<br />

b= 2 : es muss noch 2 DM eingeworfen werden<br />

73


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

– Menge der Transitionsaktionen<br />

A = {Wk, Wn, E1, E2, R1, Ak, An }, mit<br />

Wk: Wahl einer Kurzstreckenkarte<br />

Wn: Wahl einer normalen Fahrkarte<br />

E1: Einwurf eines 1DM Stückes<br />

E2: Einwurf eines 2DM Stückes<br />

R1: Rückgabe eines 1DM Stückes<br />

Ak: Ausgabe einer Fahrkarte für Kurzstrecke<br />

An: Ausgabe einer Normalfahrkarte<br />

– Zustandsübergänge<br />

(normal, 2)<br />

E1<br />

Wn Wk<br />

(Wahl, 0)<br />

E1<br />

E1<br />

(normal, 1) (normal, 0) (kurz, 0) (kurz, 1)<br />

E2<br />

E2<br />

R1<br />

An<br />

R1<br />

An<br />

Ak<br />

(normal, -1) (Wahl, -1) (kurz, -1)<br />

¯ Aktionsspur<br />

Jedem Zustandsautomaten lassen sich ausgehend von der gegebenen Menge<br />

von Anfangszuständen Spuren zuordnen.<br />

– Definition<br />

Gegeben sei ein Zustandsautomat Z = (S, A, R, S0). Eine Folge a , wobei 1<br />

i<br />

i k mit k IN { }, ist eine endliche oder unendliche Aktionsspur<br />

des Zustandsautomaten, falls eine Folge von Zuständen s existiert, mit s<br />

i i<br />

S, s S0 und<br />

1<br />

s s für alle i mit 1 i k<br />

i-1 ai i<br />

– Eine Aktion a heißt deterministisch, wenn für jeden Zustand s S höchstens<br />

ein Nachfolgezustand s S existiert mit<br />

f<br />

s s<br />

a f<br />

– Beispiel<br />

Auswertung eines Programms mit Zustandsänderung. Das Programm<br />

74<br />

Ak<br />

R1<br />

E2


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

Ý <br />

Ü <br />

ÛÐ Ü ß<br />

Ý Ü Ý Ü Ü <br />

<br />

berechnet die Fakultätsfunktion. Nach seiner Ausführung gilt 10! = y. Der<br />

Ablauf dieses Programms entspricht der sequentiellen Aktionsstruktur, deren<br />

Ereignisse, Aktionen und Zustände in der folgenden Tabelle angegeben sind.<br />

Ereignis Aktion Zustand x Zustand y<br />

a0 y = 1 undefiniert 1<br />

b0 x = 10 10 1<br />

a1 (x 0) ? 10 1<br />

b1 y=x*y 10 10<br />

c1 x=x-1 9 10<br />

... ... ... ...<br />

a10 (x 0)? 1 10!<br />

b10 y = x * y 1 10!<br />

c10 x = x - 1 0 10!<br />

a11 (x 0)? 0 10!<br />

Hier bezeichnen Aktionen wie (x 0)? Abfrageaktionen, die den<br />

Datenzustandsraum nicht ändern. Nehmen wir jedoch Kontrollzustände<br />

(etwa einen Befehlszähler) mit zu den Zuständen des Zustandsraums hinzu,<br />

so ändert auch diese Abfrage den Zustand. Zustände sind für das obige<br />

Programm durch Paare (n, m) von Zahlen gegeben, die die Werte der<br />

Programmvariablen x und y repräsentieren. Mit jeder Zuweisung in<br />

einem prozeduralen Programm wird eine Aktion verbunden, die einer<br />

Zustandsänderungsabbildung entspricht.<br />

Konflikte<br />

Im Zusammenhang mit Programmen und den ihnen zugeordneten Prozessen<br />

stellt sich die Frage, welche Zustandsänderungen ohne Schwierigkeiten zeitlich<br />

parallel durchgeführt werden können. In vielen Fällen lassen sich Aktionen<br />

zeitlich nebeneinander ausführen. Gewisse Zustandsänderungen können aber<br />

nicht ohne Konflikte nebeneinander ausgeführt werden. Wir sagen, dass diese<br />

Aktionen im Konflikt miteinander sind. Sollen beispielsweise zwei Anweisungen<br />

an die gleiche Programmvariable x parallel ausgeführt werden, so lässt sich dem<br />

entsprechenden Prozess keine Zustandsänderungsabbildung eindeutig zuordnen.<br />

In beiden Aktionen soll die Programmvariable x geändert werden. Die Aktionen<br />

sind im Konflikt.<br />

¯ Beispiel<br />

75


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

Mögliche Konflikte bei parallel durchzuführenden Zuweisungen. Wir<br />

betrachten die Aktionen, die den folgenden beiden Zuweisungen entsprechen:<br />

Ü Ü<br />

Ü Ü<br />

Die Zuweisungen stehen im Konflikt zueinander.<br />

– Werden sie parallel ausgeführt, so kann dem entsprechenden Prozess<br />

keine Zustandsänderung eindeutig zugeordnet werden; wir sagen auch, die<br />

Aktionen stören sich wechselseitig.<br />

¯ Störungsfreiheit<br />

Frage: Gibt es Kriterien, um auf einfache Weise solche Konflikte zu erkennen,<br />

so dass sie durch eine Reihenfolgeregelung gelöst werden können? Die Frage<br />

kann mit ja beantwortet werden; es gibt Kriterien, und zwar die Bernstein-<br />

Bedingungen.<br />

– Vorbereitung<br />

Für eine Transitionsaktion a gelte:<br />

V(a) S ist Vorbereich, d.h. die Menge der gelesenen Zustandsvariablen.<br />

N(a) S ist Nachbereich,<br />

Zustandsvariablen.<br />

– Beispiel<br />

Sei S = {x, y, z}<br />

d.h. die Menge der geschriebenen<br />

Ü Ü Ý Þ Î ßÜ Ý Þ Æ ßÜ<br />

Ý Ü Î ßÜ Æ ßÝ<br />

– Definition Störungsfreiheit<br />

Gegeben sei ein Prozess p= (E, , «). Der Prozess p heißt störungsfrei,<br />

genau dann, wenn für jedes Paar von Ereignissen e1, e2 E gilt:<br />

1.) e1 e2 oder e2 e1 oder<br />

2.) V(«(e1)) N(«(e2)) = N(«(e1)) V(«(e2)) = N(«(e1)) N(«(e2)) = Ø.<br />

£ Die Bedingung (2) nennt man auch Bernstein-Bedingungen. Gilt die<br />

Bernsteinbedingung, dann ist die Reihenfolge der Ausführung der beiden<br />

Zuweisungen ohne Einfluss auf den schließlich erreichten Endzustand.<br />

Der Störungsbegriff umfasst auch unerwünschte Situationen in konventionellen<br />

Rechnern, in denen ein gleichzeitiges Lesen und Schreiben,<br />

sowie mehrfaches gleichzeitiges Schreiben auf einer Speicherzelle auch<br />

technisch zu einem Konflikt führt.<br />

76


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

– Für störungsfreie Systeme gilt, dass unter Einhaltung der mit festgelegten<br />

Reihenfolge, die Ausführungsreihenfolge der parallelen Ereignisse und<br />

deren Aktionen keinen Einfluss auf die berechneten Ergebnisse hat. Die<br />

Bernstein-Bedingungen sind auch im Zusammenhang mit parallelisierenden<br />

Compilern wichtig. Parallelisierende Compiler versuchen, Anweisungen<br />

des zu compilierenden Programms, die keine gemeinsamen Datenobjekte<br />

benutzen, für eine parallele Bearbeitung vorzubereiten (z.B. Ausnutzen vieler<br />

Pipeliningstufen von RISC-Prozessoren). Dazu kann man die sequentiellen<br />

Aktionen (Anweisungen) schrittweise aus der Relation entfernen, solange<br />

die Bernsteinbedingung nicht verletzt wird.<br />

3.3.5 Petri-Netze<br />

Ein Prozess beschreibt einen möglichen Ablauf eines verteilten Systems. Verteilte<br />

Systeme besitzen viele Abläufe, d.h. ein System wird durch die Menge von<br />

Abläufen beschrieben. Gesucht wird deshalb ein Modell zur Beschreibung<br />

von Systemen und deren möglichen Abläufen. Drei Vertreter solcher<br />

Formalismen sind Petri-Netze (graphische Beschreibungsmethode), Agenten<br />

(formale Beschreibungssprache, siehe Broy Band II) und prädikatenlogische<br />

Formeln zur Beschreibung von Abläufen. Im folgenden werden Petri-Netze<br />

vorgestellt, die eine graphen-orientierte Beschreibung verteilter Systeme und<br />

deren Abläufen ermöglicht.<br />

Allgemeines<br />

Formalismus von C.A. Petri 1962 entwickelt. Ansatz führte zu einer Theorie zur<br />

Analyse und Entwicklung nebenläufiger Systeme.<br />

¯ informelle Charakterisierung<br />

Ein Petri-Netz ist gerichteter Graph mit Kanten und zweierlei Knoten.<br />

– Knoten: Stellen (graphisch Kreise) und Transitionen (graphisch Rechtecke)<br />

– Kanten: von Stellen zu Transitionen oder von Transitionen zu Stellen<br />

– Belegung der Stellen mit Marken/Werten (Token);<br />

£ In einem boolschen Netz sind als Werte nur 0 oder 1 zugelassen.<br />

£ In einem Stellen/Transitionsnetz sind für die Belegung der Stellen<br />

natürlichzahlige Werte zugelassen; die maximale Belegung definiert die<br />

Stellenkapazität.<br />

77


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

– Zustand: definiert durch Belegung der Stellen;<br />

£ Zustandsübergang durch sogenannte Schaltregeln (engl. firing rule);<br />

Belegung ändert sich. Man spricht in diesem Zusammenhang vom<br />

Schalten einer Transition. Das dynamische Verhalten eines Netzes läßt<br />

sich durch Schaltvorgänge beschreiben. Transitionen schalten, indem sie<br />

von allen Eingangsplätzen eine Marke abziehen (bei 1-wertigen Kanten)<br />

und auf allen Ausgangsplätzen eine Marke hinzufügen. Ein Schaltvorgang<br />

kann insbesondere die Gesamtzahl der Marken in einem Netz ändern. Eine<br />

einzelne Transition ist schaltbereit, wenn alle ihre Eingangsplätze echt<br />

positiv belegt sind; bei mehrwertigen Kanten müssen entsprechend viele<br />

Marken bei den Eingangsplätze vorhanden sein.<br />

– Markierung der Kanten, Kantengewichte: Gewichtung gibt an, wieviele<br />

Marken beim Schalten einer Transition von den Eingangsknoten (Stellen)<br />

der Transition abgezogen und den Ausgangsknoten (Stellen) der Transition<br />

hinzugefügt werden.<br />

¯ Beispiel eines Petri-Netzes<br />

grobe Modellierung einer Materialverwaltung.<br />

Bestellung<br />

Bestellaufnahme<br />

Produktionsauftrag<br />

Lieferauftrag<br />

Produktion<br />

Auslieferung<br />

Lager<br />

Waren<br />

Bestellungen kommen zur Bestellaufnahme, die Lieferaufträge an die<br />

Auslieferung erteilt. Diese bedient sich aus einem Lager und liefert<br />

Ware aus. Um das Lager aufzufüllen, müssen Produktionsaufträge an die<br />

Produktion erteilt werden. Aus der graphischen Darstellung ist ersichtlich,<br />

dass Transitionen Tätigkeiten repräsentieren, während Stellen eher Zustände<br />

darstellen. Marken, die Stellen zugeordnet sind und einen dynamischen Ablauf<br />

ermöglichen, werden erst weiter unten eingeführt.<br />

78


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

Definition: Petri-Netz<br />

Ein Petri-Netz ist ein Tripel (S, T, F) mit<br />

S ist eine endliche Menge von Stellen (engl. place)<br />

T ist eine endliche Menge von Transitionen (engl. transition) und es gilt: S <br />

T = Ø d.h. Stellen und Transitionen sind disjunkt.<br />

F ist die Flussrelation mit F (S ¢ T) (T ¢ S)<br />

Für einen Knoten x (S T) gilt:<br />

¡x = {y | y F x} den Vorbereich von x<br />

x¡ = {y | x F y} den Nachbereich von x<br />

x kann dabei eine Stelle oder eine Transition sein.<br />

¯ Mit obiger Definition ist die statische Struktur eines Netzes formal erfasst. Die<br />

graphische Darstellung wurde bereits anhand des obigen Beispiel gezeigt.<br />

¯ Für das Beispiel Materialverwaltung gilt beispielsweise:<br />

¡Bestellaufnahme = {Bestellung}<br />

Bestellaufnahme¡ = {Produktionsauftrag, Lieferauftrag}<br />

¯ Verfeinerung<br />

Netzstrukturen können schrittweise verfeinert, konkretisiert werden. Wichtig:<br />

Globale Struktur muss bei Verfeinerung erhalten bleiben, d.h. alle Kanten in<br />

eine verfeinerte Transition und alle Kanten aus dieser verfeinerten Transition<br />

bleiben erhalten. Die innere Struktur der Transition kann wiederum in<br />

Stellen, Transitionen und Kanten aufgeschlüsselt werden. Die zu verfeinernde<br />

Transition kann nach außen hin als Blackbox gesehen werden.<br />

– Beispiel<br />

Verfeinerung der Materialverwaltung: z.B. der Komponente Auslieferung.<br />

Anhand des Lieferauftrages wird der Lieferschein geschrieben, der zusammen<br />

mit dem Produkt verpackt und versandt wird.<br />

79


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

Lieferauftrag<br />

Lager<br />

Lieferscheinerstellung<br />

Lieferschein<br />

Verpacken<br />

Auslieferung<br />

Versenden<br />

verpackte<br />

Produkte<br />

Auslieferung ist nach außen hin eine Transition.<br />

Markierung und Schaltregeln<br />

Waren<br />

Zur Erfassung des dynamischen Verhaltens erweitern wir die Definition eines<br />

Petri-Netzes zunächst um Markierungen und geben dann die Schaltregeln an.<br />

¯ Markierung<br />

Gegeben sei ein Petri-Netz (S, T, F).<br />

– Eine Abbildung c: S IN { } gibt die Kapazität einer Stelle an. Wenn<br />

in den von uns verwendeten Netzen die Stellen nicht explizit markiert sind,<br />

dann bedeutet dies eine unbeschränkte Kapazität.<br />

– Eine Abbildung w: F IN {0} gibt die Gewichtung einer Kante an. Wenn<br />

in den von uns verwendeten Netzen die Kanten nicht explizit markiert sind,<br />

dann bedeutet dies eine implizite Gewichtung mit dem Gewicht 1.<br />

– Eine Abbildung M: S IN heißt natürlichzahlige Markierung der Stellen.<br />

Die Markierung beschreibt einen Zustand des Netzes.<br />

Es muss gelten: s S: M(s) c(s)<br />

Ein solches Netz heißt Stellen-Transitionsnetz<br />

– Falls gilt M: S IB, dann heißt das Netz: Bedingungs/Ereignisnetz<br />

oder Boolesches Netz. Demnach entsprechen Boolsche Petri-Netze<br />

natürlichzahligen Petri-Netzen, bei denen jede Stelle die Kapazität 1 hat<br />

(oder einen boolschen Wert mit true (=1) bzw. false (=0) hat). Eine Transition<br />

80


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

t kann nur dann schalten, wenn alle Stellen, zu denen Kanten von t aus führen,<br />

mit false markiert sind.<br />

¯ Schaltregeln<br />

Das Verhalten eines Netzes wird durch Schaltvorgänge beschrieben. Gegeben<br />

sei ein Petri-Netz (S, T, F), die Funktionen c, w und eine Anfangsmarkierung<br />

M0.<br />

– Ein Zustandsübergang erfolgt durch das Schalten von Transitionen, wobei<br />

gilt: Eine Transition t T kann schalten (ist transitionsbereit), wenn folgende<br />

Bedingungen erfüllt sind:<br />

Für alle s ¡tgilt: M(s) w((s,t))<br />

Für alle s t¡ gilt: M(s) c(s) - w((t,s))<br />

w(s,t) spezifiziert die für die Kante s t erforderliche Marken. Der zweite<br />

Fall bedeutet, dass vor Schalten der Transition die aktuelle Markierung der<br />

Stelle kleiner oder gleich als die Kapazität der Stelle minus der zugehörigen<br />

Kantengewichtung ist.<br />

– Durch das Schalten von t wird eine Folgemarkierung M' zu M erzeugt, mit<br />

Für alle s ¡t\t¡ gilt: M'(s) = M(s) - w((s,t))<br />

Für alle s t¡ \ ¡t gilt: M'(s) = M(s) + w((t,s))<br />

Für alle s (¡t t¡) gilt: M'(s) = M(s) - w((s,t)) + w((t,s))<br />

Sonst: M'(s) = M(s)<br />

– Das Modell trifft keine Festlegungen über die Schaltdauer einer Transition,<br />

man geht davon aus, dass das Schalten keine Zeit erfordert. Die Definition<br />

besagt, dass eine Transition nur schalten kann, wenn in ihren Eingangsstellen<br />

mindestens soviele Marken liegen, wie die Gewichtung der jeweiligen<br />

Kanten angibt und wenn außerdem gewährleistet ist, dass durch das Schalten<br />

die Kapazität ihrer Ausgangstellen nicht überschritten wird. Durch das<br />

Schalten werden entsprechend der Kantengewichtung Marken von allen<br />

Eingangstellen abgezogen und ebenfalls entsprechend der Gewichtung<br />

Marken den Ausgangstellen hinzugefügt.<br />

– Beispiel: Schalten einer Transition<br />

Gegeben sei eine Kantengewichtungsfunktion w, die jede Kante mit 1<br />

gewichtet, also<br />

w: F 1<br />

81


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

vor dem Schalten nach dem Schalten<br />

– Beispiel: Schalten mit Kantengewicht<br />

2<br />

3<br />

vor dem Schalten nach dem Schalten<br />

– Beispiel: nichtschaltbare Transition<br />

In der linken Situation enthält die Stelle s2 zu wenige Tokens, da gemäß<br />

der Kantenmarkierung bei jedem Schalten der Transition t1 zwei Marken<br />

von der Stelle s2 konsumiert werden. In der rechten Situation liegt dagegen<br />

ein Markenüberfluss vor. Die Transition t1 kann nicht schalten, da auf<br />

der Stelle s4 bereits ein Token liegt und damit die Kapazität der Stelle (1)<br />

bereits erschöpft ist. Durch ein Schalten würde ein weiteres Token der Stelle<br />

hinzugefügt werden und die Kapazität überschreiten.<br />

s1<br />

s2<br />

t1 s3 s1<br />

t1<br />

s4<br />

s2<br />

2 2<br />

Markenmangel Markenüberfluss bei s4<br />

82<br />

2<br />

3<br />

s3<br />

s4<br />

Kapazität 1


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

Animation Petrinetz<br />

siehe online Version<br />

Nebenläufigkeit<br />

Mit Petri-Netzen lassen sich nebenläufige Systeme auf einfache Weise modellieren.<br />

Betrachten wir zum Beispiel vier Aktivitäten t1, ... , t4, wobei jede Aktivität<br />

durch eine Transition modelliert wird. Nach Beendigung von t1 (z.B. Einlesen<br />

von Eingabewerten) können t2 (z.B. Berechne ggt) und t3 (z.B. Berechne Fibonacci)<br />

nebenläufig aktiv sein, aber sie müssen beide beendet sein, bevor t4 ausgeführt<br />

wird.<br />

t1<br />

t2<br />

t3<br />

¯ Nichtdeterminismus<br />

Bei einer gegebenen Markierung M können Konflikte hinsichtlich der<br />

Schaltbereitschaft von Transitionen auftreten. Zwei Transitionen t1 und t2 sind<br />

im Konflikt, wenn sie gemeinsame Eingangs- und Ausgangsstellen besitzen, die<br />

so markiert sind, dass nur eine von beidem Transitionen schalten kann. Es<br />

erfolgt eine nichtdeterministische Auswahl.<br />

– Beispiel<br />

Erzeuger/Verbraucher mit Konfliktbelegung. Nach dem nebenläufigen<br />

Schalten der Transitionen a und b des Netzes (siehe Situation oben) ergibt<br />

sich eine Konfliktbelegung (siehe Situation unten), in der nur entweder die<br />

Transition c oder die Transition d schalten kann.<br />

83<br />

t4


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

a c e d b<br />

Erzeuger Verbraucher<br />

a c e d b<br />

Eigenschaften von Netzen<br />

nebenläufiges<br />

Schalten<br />

Konflikt<br />

belegung<br />

bzgl c und d<br />

Für ein gegebenes Petri-Netz, das das Verhalten eines verteilten Systems<br />

modelliert, sind wir daran interessiert, zu klären, ob das System bei gegebener<br />

Anfangsmarkierung bestimmte Eigenschaften besitzt. Eigenschaften sind die<br />

Erreichbarkeit und die Lebendigkeit.<br />

¯ Erreichbarkeit<br />

Häufig ist man an der Frage interessiert, ob das Netz ausgehend von einer<br />

Markierung M irgendwann eine Folgemarkierung M' erreicht. Das ist die Frage<br />

der Erreichbarkeit von Zuständen.<br />

– Erreichbare Markierung<br />

Gegeben sei ein Petri-Netz (S, T, F) mit der Markierung M. Eine endliche<br />

Sequenz = t1, t2, ..., tn mit t T heißt von M aktivierte endliche<br />

i<br />

Schaltfolge, wenn Markierungen M1, M2, ..., Mn existieren mit<br />

t1<br />

M M1<br />

t2<br />

M2<br />

tn<br />

Mn<br />

ρ<br />

d.h. M Mn<br />

£ M' ist von M erreichbar, wenn es eine Sequenz gibt, die von M<br />

in den Endzustand M' führt. Um die erreichbaren Markierungen eines<br />

Netzes zu erfassen, modelliert man das Netz als einen Zustandsautomat,<br />

84


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

der üblicherweise als Graph dargestellt wird (Erreichbarkeitsgraph). Die<br />

Knoten des Graphen sind die erreichbaren Markierungen und die Kanten<br />

sind mit Transitionen beschriftet.<br />

– Beispiel: Bahnnetz<br />

Vier Städte sind durch Bahngleise, die nur in einer Richtung befahrbar sind,<br />

im Kreis verbunden. Zwei Züge fahren auf der Strecke.<br />

Aufgabe: Das System ist so zu konstruieren, dass sich niemals beide Züge<br />

auf derselben Strecke befinden.<br />

Lösung: Die Strecken werden mit Stellen s1, ... , s4 modelliert. Eine<br />

Marke auf der Stelle s bedeutet, dass ein Zug auf der i-ten Strecke fährt.<br />

i<br />

Durch die zusätzlichen Kontrollstellen k1, .. , k4 soll garantiert werden,<br />

dass in keiner erreichbaren Markierung mehr als eine Marke auf einer der<br />

Stellen s liegt. k kontrolliert den Zugang zur Strecke s (Stelle).<br />

i i i<br />

t3<br />

t4<br />

t3<br />

s4 k4<br />

s1<br />

s3<br />

k1, s2, k3, s4<br />

k1<br />

k3<br />

t2 t4<br />

k2<br />

k1, k2, s3, s4 s1, s2, k3, k4<br />

t4<br />

s1, k2, s3, k4<br />

k1, s2, s3, k4 s1, k2, k3, s4<br />

t2<br />

t1 t3<br />

t1<br />

t1<br />

t2<br />

s2<br />

Bahnnetz<br />

Erreichbarkeitsgraph<br />

Die Zustände werden durch die Menge der markierten Stellen in einer<br />

erreichbaren Markierung beschrieben. Der Erreichbarkeitsgraph zeigt, dass<br />

kein Zustand ereichbar ist, in dem mehr als eine Marke, also mehr als ein<br />

Zug, auf einer Stelle s i liegt. Damit ist die gewünschte Eigenschaft korrekt<br />

85


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

modelliert. Die Frage, ob es einen Algorithmus gibt, der entscheidet, ob<br />

eine Markierung aus einer gegebenen Anfangsmarkierung aus erreichbar<br />

ist oder nicht, (Entscheidbarkeit des Erreichbarkeitsproblems), war ca. 10<br />

Jahre lang offen. Prof. E.W. Mayr hat die Entscheidbarkeit 1980 in seiner<br />

Dissertation (an der TUM) bewiesen. Aber: der Algorithmus besitzt sehr<br />

hohe Komplexität, er ist nicht effizient durchführbar.<br />

¯ Lebendigkeitseigenschaften<br />

Wie zu Beginn des Kapitels bereits erwähnt, verwendet man Systemmodelle<br />

häufig, um Lebendigkeitseigenschaften zu analysieren. Stellen-<br />

Transitionsnetze werden oft in Bereichen verwendet, in denen es auf die Anzahl<br />

und die Verteilung veränderlicher Objekte ankommt. (z.B. Daten in einem<br />

Rechner, Waren in einem Lager, Werkstücke). Man ist daran interessiert zu<br />

erkennen, ob es in einem System zu Blockierungen kommen kann, so dass Teile<br />

des Systems blockiert sind oder der gesamte Ablauf zum Stillstand kommt. Ursachen<br />

für solche Situationen sind Mangel oder Stau, der durch die veränderlichen<br />

Objekte ausgelöst wird.<br />

– Netzdarstellung<br />

aktive Systemelemente als Transitionen (Prozessor, Maschine, etc.)<br />

passive Systemteile als Stellen (Speicher, Lager, etc.)<br />

veränderliche Objekte als Marken<br />

Für Lebendigkeitsuntersuchungen sind Netzteile interessant, die niemals<br />

markiert werden oder die niemals ihre Marken verlieren.<br />

– Definition<br />

Gegeben sei ein Petri-Netz (S, T, F) mit der Anfangsmarkierung M0.<br />

£ Das Netz heißt lebendig, wenn für jede erreichbare Markierung M und für<br />

jede Transition t T eine Markierung M' existiert, die aus M erreichbar ist<br />

und in der t transitionsbereit ist. Informell: jede Transition t kann immer<br />

wieder schalten.<br />

£ Die von M0 aus erreichbare Markierung M beschreibt eine vollständige<br />

Verklemmung (eng. deadlock), wenn es keine Transition t T gibt, die<br />

unter M schalten kann.<br />

£ Die von M0 aus erreichbare Markierung M beschreibt eine lokale<br />

Verklemmung, wenn es eine Transition t T gibt, so dass ausgehend von<br />

M keine Folgemarkierung M' erreichbar ist, in der t transitionsbereit ist.<br />

£ Ist (S, T, F) mit Anfangsmarkierung M0 lebendig, dann ist es auch<br />

verklemmungsfrei. Lebendige Netze stellen sicher, dass es weder zu<br />

einem Markenmangel noch zu einem Überfluss kommt. Die Eigenschaft<br />

86


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

der Lebendigkeit eines Netzes ist insbesondere für Systeme, die für einen<br />

Endlosbetrieb ausgelegt sind (z.B. Betriebssysteme) wichtig.<br />

– Beispiel: Lebendiges Netz<br />

Aufgabe: Modellierung eines FIFO-Puffers mit Kapazität 3. Und zwar so,<br />

dass er verklemmungsfrei und lebendig ist.<br />

Lösung: Das System besteht aus 3 Zellen, die jeweils eine Nachricht<br />

aufnehmen können die Stellen repräsentieren die Speicherzellen). Die<br />

Transition t1 modelliert das Eingeben einer neuen Nachricht und die<br />

Transition t4 modelliert die Ausgabe der Nachricht. Mit den Transitionen<br />

t werden die Nachrichten von Zelle s zur Zelle s weitergereicht.<br />

i i-1 i<br />

Voraussetzung ist, dass die entsprechende Zelle leer ist. Der Zustand "Zelle<br />

s ist leer", wird durch die markierte Stelle k modelliert.<br />

i i<br />

Das modellierte Netz ist verklemmungsfrei und lebendig. Falls der FIFO<br />

Puffer in ein größeres System eingebunden ist, müssen die Transition t1 (für<br />

die Eingabe von Nachrichten) und t4 (für die Ausgabe von Nachrichten) in<br />

das Gesamtsystem integriert werden.<br />

t1 t2 t3 t4<br />

Eingabe einer<br />

Nachricht<br />

k1 k2 k3<br />

s1 s2 s3<br />

Ausgabe einer<br />

Nachricht<br />

– Beispiel: Verklemmung<br />

2 Studenten benötigen ein 2-bändiges Lehrbuch. Student 1 leiht sich<br />

zunächst nur Band 1 aus und Student 2 leiht sich vorsorglich den noch<br />

vorhandenen Band 2 aus. Bevor Student 1 seinen ersten Band zurückgibt,<br />

möchte er noch den zweiten ausleihen. Auch Student 2 gibt seinen<br />

ausgeliehenen Band nicht zurück, sondern versucht, den ersten Band<br />

auszuleihen.<br />

£ Vor der Ausleihe<br />

Anfangszustand des Netzes vor der Ausleihe. Die nachfolgende<br />

Abbildung zeigt zunächst das Netz, bevor einer der Studenten ein Buch<br />

ausleiht und die zweite Abbildung zeigt das Netz, nachdem die Studenten<br />

die jeweiligen Bände ausgeliehen haben.<br />

87


Schlichter, TU München 3.3. MODELLIERUNG PARALLELER SYSTEME<br />

Student 1 Band1 Band 2 Student 2<br />

Band 1<br />

ausleihen<br />

Band 2<br />

ausleihen<br />

beide Bände<br />

zurückgeben<br />

Band 2<br />

ausleihen<br />

Band 1<br />

ausleihen<br />

beide Bände<br />

zurückgeben<br />

£ Nach der Ausleihe<br />

Zustand des Netzes nach dem Schalten Transitionen, d.h. nach der<br />

Ausleihe. Diese Abbildung zeigt, dass das Netz verklemmt ist; es<br />

gibt keinen Systemfortschritt mehr. Was ist das Problem unseres<br />

Modells? Bei Student 1 und Student 2 haben die Ausleihe der Bänder<br />

unterschiedliche Reihenfolgen; bei gleicher Reihenfolge der Ausleihe tritt<br />

keine Verklemmung ein.<br />

88


Schlichter, TU München 3.4. THREAD-KONZEPT<br />

Student 1 Band1 Band 2 Student 2<br />

Band 1<br />

ausleihen<br />

Band 2<br />

ausleihen<br />

beide Bände<br />

zurückgeben<br />

¯ Weitere interessante Eigenschaften: nur ganz informell:<br />

Band 2<br />

ausleihen<br />

Band 1<br />

ausleihen<br />

beide Bände<br />

zurückgeben<br />

– Fairness<br />

Gegeben sei ein Netz N mit Anfangsmarkierung M. Das Netz ist unfair für<br />

eine Transition t, wenn es eine unendliche Sequenz gibt, in der t nur endlich<br />

oft auftritt, obwohl t unendlich oft transitionsbereit ist.<br />

– Verhungern<br />

t verhungert (engl. Starvation): Es gibt eine unendliche Sequenz, in<br />

der die Transition t niemals auftritt. Falls unfaire Sequenz: trotz<br />

Transitionsbereitschaft von t.<br />

3.4 Thread-Konzept<br />

Threads sind ein BS-Konzept für die Modellierung und Realisierung von<br />

nebenläufigen Aktionen in einem Rechensystem. Threads (Kontrollflüsse)<br />

beschreiben die Aktivitäten in einem Rechensystem. Sie können als virtuelle<br />

Prozessoren aufgefasst werden, die jeweils für die Ausführung eines zugeordneten<br />

Programms in einem Adressraum verantwortlich sind. Threads konkurrieren um<br />

die physische CPU, um ablaufen zu können. In traditionellen Umgebungen hat<br />

89


Schlichter, TU München 3.4. THREAD-KONZEPT<br />

jeder Prozess genau einen Thread, der den Kontrollfluss des Prozess repräsentiert,<br />

während in Multithreaded-Umgebungen ein Prozess mehrere Threads besitzen<br />

kann.<br />

Prozess<br />

Thread<br />

Betriebssystem<br />

3.4.1 Charakterisierung von Threads<br />

Thread<br />

Benutzer<br />

Adressraum<br />

Aus BS-Sicht ist ein Prozess definiert<br />

durch einen Adressraum<br />

eine darin gespeicherte Handlungsvorschrift in Form eines sequentiellen<br />

Programms<br />

einen oder mehreren Aktivitätsträgern, die dynamisch die<br />

Handlungsvorschrift ausführen Threads<br />

Motivation<br />

Ein Thread ist die Abstraktion eines physischen Prozessors; er ist ein Träger einer<br />

sequentiellen Aktivität. Gründe für die Einführung von Threads:<br />

¯ mehrere Threads ermöglichen Parallelität innerhalb eines Prozesses unter<br />

Nutzung des gemeinsamen Adressraums. Durch die Nutzung des gemeinsamen<br />

Adressraums wird die Interaktion zwischen den Threads (Kommunikation und<br />

gemeinsame Nutzung von Daten) erleichtert. Jeder Thread für sich gesehen<br />

repräsentiert ein streng sequentielles Verarbeitungsmodell.<br />

¯ Aufwand für Erzeugen und Löschen von Threads ist geringer als für Prozesse.<br />

Threads führen nicht so einen großen Ballast an Information mit sich als<br />

Prozesse. Beispielsweise muss bei der Erzeugung eines Prozesses durch<br />

das BS ein neuer Adressraum generiert werden; Threads laufen im bereits<br />

vorhandenen Adressraum ab. Deshalb spricht man bei Threads auch von<br />

90


Schlichter, TU München 3.4. THREAD-KONZEPT<br />

Leichtgewichtsprozesse ("light weight processes"), da sie erheblich weniger<br />

Verwaltungsinformation als normale Prozesse ("heavy weight processes")<br />

benötigen.<br />

¯ Verbesserung der Performanz der Applikationsausführung durch Nutzung<br />

mehrerer Threads. Dieses Argument ist besonders dann von Bedeutung, wenn<br />

die Applikation (und damit der zugehörige Prozess) sowohl CPU- als auch E/Aintensive<br />

Aktivitäten beinhaltet. E/A-Wartezeiten innerhalb einer Applikation<br />

können durch andere rechenbereite Threads der Applikation genutzt werden.<br />

Dagegen gewinnen CPU-dominierte Applikationen durch die Parallelisierung<br />

mittels Threads weniger an Performanz (falls nur eine CPU zur Verfügung<br />

steht).<br />

¯ Threads ermöglichen bei einem Multiprozessor-Rechensystem echte Parallelität<br />

innerhalb einer Applikation.<br />

Prozess vs. Thread<br />

Prozesse und Threads haben unterschiedliche Zielsetzungen:<br />

Prozesse gruppieren Ressourcen,<br />

Threads sind Aktivitätsträger, die zur Ausführung einer CPU zugeteilt<br />

werden.<br />

¯ Threadspezifische Information<br />

Jeder Thread umfasst eine Reihe von Informationen, die seinen aktuellen<br />

Zustand charakterisieren:<br />

Befehlszähler, aktuelle Registerwerte, Keller, Ablaufzustand des Thread.<br />

Ebenso wie ein Prozess befindet sich ein Thread in einem der nachfolgenden<br />

Zustände: rechenwillig, rechnend, wartend, terminiert. Entsprechend den<br />

ausgeführten Aktionen (z.B. Ein-/Ausgabe) und der Zuteilung bzw. des<br />

Entzugs der CPU finden Zustandsübergänge statt. Jeder Thread hat seinen<br />

eigenen Keller, in dem die Unterprogrammaufrufe verwaltet werden. Jeder<br />

Thread hat seinen eigenen Satz an Registern (darunter auch den Befehlszähler),<br />

die gerettet werden müssen, falls einem Thread die CPU entzogen wird. Bei<br />

einer CPU-Zuteilung werden die geretteten Registerwerte des Threads in die<br />

jeweiligen Register geladen.<br />

¯ Prozessspezifische Information<br />

Die nachfolgende Information/Ressourcen wird von allen Threads eines<br />

Prozesses geteilt. Jeder Thread kann sie verwenden bzw. darauf zugreifen.<br />

91


Schlichter, TU München 3.4. THREAD-KONZEPT<br />

Adressraum, globale Variable, offene Dateien, Kindprozesse (z.B. erzeugt<br />

mit fork), eingetroffene Alarme bzw. Interrupts.<br />

Dies sind Eigenschaften des Prozesses und nicht eines einzelnen Threads.<br />

Beispielsweise, wenn ein Thread eine Datei öffnet, dann ist diese Datei auch<br />

für die anderen Threads sichtbar, und sie können in sie schreiben bzw. aus ihr<br />

lesen. Diese Information ist i.a. zwischen Prozessen nicht sichtbar, außer dass<br />

vom Vaterprozess an den Kindprozess Dateideskriptoren vererbt werden.<br />

Beispiel: Web-Server<br />

Ein Prozess kann mehrere Threads umfassen, die unterschiedliche Aufgaben<br />

übernehmen. Beispielsweise kann ein Web-Server einen Verteiler-Thread<br />

("dispatcher") und mehrere Server-Threads ("worker-thread") umfassen.<br />

Anforderung<br />

Verteiler-<br />

Thread<br />

Netzwerk-Verbindung<br />

Web-Serverprozess<br />

Betriebssystem<br />

Server-<br />

Thread<br />

Benutzer<br />

Adressraum<br />

Auf diese Weise ist es möglich den Server als eine Menge von sequentiellen<br />

Threads zu realisieren. Der Verteiler-Thread ist eine unendliche Schleife, die die<br />

Schnittstelle für den Eingang von Service-Anforderungen darstellt.<br />

¯ Der Verteiler-Thread dient zur Annahme von Service-Anforderungen und gibt<br />

sie weiter an einen der Server-Threads zur Bearbeitung. Server-Threads<br />

können bei Eintreffen einer Service-Anforderung jeweils dynamisch erzeugt<br />

werden, und nach Erledigung der Anforderung bzw. nach Zustellung der<br />

Antwort terminiert werden. Zur Verbesserung der Antwortzeiten kann der<br />

Web-Server bereits einen Pool von Server-Threads erzeugen, denen jeweils<br />

dynamisch Anforderungen zugeteilt werden können. Server-Threads werden<br />

nach Bearbeitung einer Anforderung nicht beendet, sondern wieder in den Pool<br />

92


Schlichter, TU München 3.4. THREAD-KONZEPT<br />

der freien Server-Threads eingereiht. Bei Bedarf können zusätzliche Server-<br />

Threads erzeugt werden, falls alle Server-Threads aus dem Pool bereits belegt<br />

sind.<br />

¯ Alle Server-Threads nutzen den gemeinsamen Web-Cache.<br />

3.4.2 Threads in Java<br />

Java unterstützt die <strong>Programmierung</strong> mit Threads, um nebenläufige Abläufe<br />

innerhalb einer Applikation zu ermöglichen. Java Threads können sowohl in Java-<br />

Programmen als auch in Java-Applets verwendet werden. Die Implementierung<br />

der Java Virtual Machine selbst beruht auf Threads: Der Java-Müllsammler<br />

(Garbage collector) ist z.B. ein Thread zum Sammeln von nicht länger<br />

referenzierten Objekten, der nebenläufig zum Java Programm abläuft. Hier<br />

erfolgt nur eine sehr kurze Wiederholung einiger der Aspekte, die bereits in der<br />

Informatik-Einführungsvorlesung behandelt wurden.<br />

Definition<br />

Threads können durch Implementierung der Schnittstelle ÊÙÒÒÐ realisiert<br />

werden. Eine weitere Möglichkeit besteht durch SubClassing der Klasse Thread<br />

selbst, d.h.<br />

ÔÙÐ Ð×× ÊØÙÖÒ×Ø ÜØÒ× ÌÖ ß <br />

¯ Thread Implementierungen überschreiben die run-Methode der Schnittstelle<br />

Runnable.<br />

ÔÙÐ Ð×× ÐÐ ×Ø ÑÔÐÑÒØ× ÊÙÒÒÐ ß<br />

<br />

ÔÙÐ ÚÓ ÖÙÒ ß <br />

¯ Thread Instanzen werden durch den Aufruf der start-Methode der Schnittstelle<br />

Runnable gestartet. Diese Methode sollte durch eine Thread-Implementierung<br />

nicht verändert werden. Die start-Methode ruft die run-Methode auf, wodurch<br />

die Instanz der Thread-Implementierung ausgeführt wird.<br />

ÔÙÐ ×ØØ ÚÓ ÑÒ ËØÖÒ℄ Ö× ß<br />

<br />

ÐÐ ×Ø ÒÛ ÐÐ ×Ø <br />

ÌÖ Ø ÒÛ ÌÖ <br />

Ø ×ØÖØ <br />

93


Schlichter, TU München 3.4. THREAD-KONZEPT<br />

Ergebnisrückgabe<br />

Der Ablauf der Threads ist asynchron, d.h. die Ausführungsreihenfolge einer<br />

Menge von Threads ist nicht fest vordefiniert. Dies ist insbesondere bei<br />

kooperierenden Threads von Bedeutung, z.B. bei der Ergebnisrückgabe eines<br />

Thread an einen anderen Thread. Die Ausführungsreihenfolge ergibt sich<br />

durch die CPU-Zuteilung (Scheduling) durch das Betriebssystem oder das<br />

Laufzeitsystem. Dies bedeutet, dass bei der Kommunikation zwischen Threads<br />

nicht von einem bestimmten Zeitverhalten der Threads ausgegangen werden kann,<br />

d.h. wann welche Threads ausgeführt werden.<br />

¯ Direkter Ansatz<br />

Angenommen jeder Thread liest eine Datei und erzeugt daraus die zugehörige<br />

Hash-Information (z.B. verwendet für verschlüsselte Datenübertragung).<br />

ÔÙÐ Ð×× ÊØÙÖÒ×Ø ÑÔÐÑÒØ× ÊÙÒÒÐ ß<br />

ÔÖÚØ Ð ÒÔÙØ<br />

ÔÖÚØ ÝØ℄ ×Ø<br />

ÔÙÐ ÊØÙÖÒ×Ø Ð ÒÔÙØ ß Ø× ÒÔÙØ ÒÔÙØ <br />

ÔÙÐ ÚÓ ÖÙÒ ß<br />

<br />

×Ø <br />

<br />

ÔÙÐ ÝØ℄ Ø×Ø ß ÖØÙÖÒ ×Ø <br />

ÔÙÐ Ð×× ÊØÙÖÒ×ØÍ×ÖÁÒØÖ ß<br />

<br />

ÔÙÐ ×ØØ ÚÓ ÑÒ ËØÖÒ℄ Ö× ß<br />

<br />

ÓÖ ÒØ Ö× ÐÒØ ß<br />

Ð ÒÛ Ð Ö×℄ <br />

ÊØÙÖÒ×Ø Ö ÒÛ ÊØÙÖÒ×Ø <br />

ÌÖ Ø ÒÛ ÌÖ Ö Ø ×ØÖØ <br />

<br />

ÝØ℄ ×Ø Ö Ø×Ø <br />

Jeder Thread speichert das Ergebnis der Dateibearbeitung in der Variablen<br />

digest, auf die über die Methode getDigest zugegriffen werden kann.<br />

94


Schlichter, TU München 3.4. THREAD-KONZEPT<br />

– Die Ausführung führt zu dem Fehler<br />

Ü ÔØÓÒ Ò ØÖ ÑÒ Ú ÐÒ ÆÙÐÐÈÓÒØÖÜ ÔØÓÒ<br />

Ø ÊØÙÖÒ×ØÍ×ÖÁÒØÖ ÑÒ<br />

Die Variable digest wird vor der Thread-Initalisierung benutzt. Dies liegt<br />

daran, dass das Hauptprogramm nach der Erzeugung des Thread Zugriff<br />

auf die Variable digest erhält, ohne dass der Thread die Möglichkeit der<br />

Intialisierung bzw. zur Berechnung des Wertes für ×Ø erhielt. In einer<br />

single-threaded Umgebung würde dieses Programm korrekt ablaufen, da<br />

nach Ø ×ØÖØ sofort der entsprechende Thread ausgeführt wird. In einer<br />

multi-threaded Umgebung laufen die Threads dagegen asynchron ab, d.h.<br />

die CPU-Zuteilung hängt vom Laufzeitsystem (bzw. Betriebssystem ab).<br />

Man könnte nun den main-Thread künstlich verzögern, jedoch es besteht<br />

eine "Race-Condition" zwischen den kooperierenden Threads und man kann<br />

keine Aussage über die Java Virtual Machine machen, wann welcher Thread<br />

rechnend gesetzt wird.<br />

¯ Callback Ansatz<br />

Nicht das main-Programm holt die Ergebnisse ab, sondern die aufgerufenen<br />

Threads rufen jeweils eine Methode des main-Programms auf, um die<br />

Ergebnisse zu übergeben Callback<br />

ÔÙÐ Ð×× ÐÐ ×Ø ÑÔÐÑÒØ× ÊÙÒÒÐ ß<br />

ÔÖÚØ Ð ÒÔÙØ<br />

ÔÙÐ ÐÐ ×Ø Ð ÒÔÙØ ß Ø× ÒÔÙØ ÒÔÙØ <br />

ÔÙÐ ÚÓ ÖÙÒ ß<br />

<br />

ÝØ℄ ×Ø <br />

ÐÐ ×ØÍ×ÖÁÒØÖ Ö Ú×Ø ×Ø <br />

<br />

ÔÙÐ ÝØ℄ Ø×Ø ß ÖØÙÖÒ ×Ø <br />

ÔÙÐ Ð×× ÐÐ ×ØÍ×ÖÁÒØÖ ß<br />

95


Schlichter, TU München 3.5. SYNCHRONISATION<br />

<br />

ÔÙÐ ×ØØ ÚÓ Ö Ú×Ø ÝØ℄ ×Ø ß<br />

<br />

ÔÙÐ ×ØØ ÚÓ ÑÒ ËØÖÒ℄ Ö× ß<br />

<br />

ÓÖ ÒØ Ö× ÐÒØ ß<br />

Ð ÒÛ Ð Ö×℄ <br />

ÊØÙÖÒ×Ø Ö ÒÛ ÊØÙÖÒ×Ø <br />

ÌÖ Ø ÒÛ ÌÖ Ö Ø ×ØÖØ <br />

<br />

Im Gegensatz zum main-Programm des direkten Ansatzes dient das main-<br />

Programm dieses Ansatzes nur zum Starten der verschiedenen Threads. Es<br />

versucht nicht die Berechnungen der getriggerten Threads direkt zu lesen und<br />

zu verarbeiten. Dies wird durch separate Methode Ö Ú×Ø erledigt.<br />

3.5 Synchronisation<br />

Eine wichtige Systemeigenschaft<br />

betrifft die Synchronisation paralleler Ereignisse, z.B. In einem<br />

Rechensystem konkurrieren parallele Aktivitäten um wiederholt exklusiv (d.h. zu<br />

einem Zeitpunkt darf höchstens eine Aktivität die Ressource nutzen) benutzbare<br />

Ressourcen, wie beispielsweise die CPU, den Drucker etc. Zusätzlich dazu können<br />

aber parallele Aktivitäten auch kooperieren, indem sie Daten über gemeinsam<br />

benutzte exklusive Objekte austauschen oder sich Nachrichten zusenden. In<br />

all diesen Fällen haben wir das Problem, den wechselseitigen Ausschluss (engl.<br />

mutual exclusion) zu gewährleisten, d.h. sicherzustellen, dass nur höchstens ein<br />

Prozess zu einem gegebenen Zeitpunkt eine exklusiv benutzbare Ressource belegt.<br />

3.5.1 Beispiele<br />

Die beiden Beispiele basieren auf der speicherbasierten Prozessinteraktion,<br />

d.h. Prozesse (oder auch Threads) interagieren über gemeinsam zugreifbare<br />

Speicherzellen.<br />

96


Schlichter, TU München 3.5. SYNCHRONISATION<br />

Beispiel: gemeinsame Daten<br />

P1 und P2 sind nebenläufige Prozesse, die in einem Multiprozessorsystem (z.B.<br />

MI) parallel ablaufen. Die Variable x ist gemeinsame Variable. Prozess P1 läuft<br />

auf CPU 0 mit Prozess P2 auf CPU 1 gleichzeitig ab. Das Problem ergibt sich auch<br />

bei quasiparallelem Ablauf (zeitliche Verschränkung der Arbeit der Prozesse). Z<br />

sei ein Zeitpunkt nach Ausführung der Aktionen A und B. Welchen Wert hat x<br />

zum Zeitpunkt Z?<br />

Das Ergebnis des Ablaufs kann je nach zeitlichem Ablauf x = 1, 2, 3 sein.<br />

Der grundlegende Nichtdeterminismus der Nebenläufigkeit wegen der Asynchronität<br />

schlägt hier auf die Ergebnisse der Prozesse durch.<br />

Zeitpunkt Z<br />

int x; x = 0<br />

Prozess P1 Prozess P2<br />

A: x = x + 1<br />

B: x = x + 2<br />

¯ Das Ergebnis ist vom zeitlichen Ablauf abhängig. Es sind folgende Fälle<br />

möglich:<br />

– Fall 1<br />

P1 liest x = 0, erhöht, speichert x = 1;<br />

P2 liest x = 1, erhöht, speichert x = 3; = Wert von x = 3<br />

– Fall 2<br />

P2 liest x = 0, erhöht, speichert x = 2;<br />

P1 liest x = 2, erhöht, speichert x = 3; = Wert von x = 3<br />

– Fall 3<br />

P1 und P2 lesen x = 0;<br />

P1 erhöht, speichert x = 1;<br />

P2 erhöht, speichert x = 2; = Wert von x = 2<br />

97


Schlichter, TU München 3.5. SYNCHRONISATION<br />

– Fall 4<br />

P1 und P2 lesen x = 0;<br />

P2 erhöht, speichert x = 2;<br />

P1 erhöht, speichert x = 1; = Wert von x = 1<br />

¯ Verhinderung des Nichtdeterminismus nur dadurch möglich, dass man<br />

garantiert, dass die Veränderung von x in den beiden Prozessen unter wechselseitigem<br />

Ausschluss (engl. mutual exclusion) erfolgt. Die Asynchronität der<br />

Prozesse muss also genau an dieser Stelle eingeschränkt werden.<br />

Erzeuger-Verbraucher-Problem<br />

Ein Beispiel für einen synchronisierten Zugriff auf eine gemeinsame Ressource,<br />

nämlich einen Puffer, haben wir bereits kennengelernt. Interpretiert man das<br />

bereits angesprochene Petri-Netz (siehe Seite 83) als eine Komposition aus<br />

drei Teilen:<br />

einem Erzeuger von Nachrichten (links),<br />

einem Puffer für Nachrichten (Mitte) und<br />

einem Verbraucher von Nachrichten (rechts).<br />

So kann man sehen, dass durch diese Modellierung gewährleistet wird, dass<br />

Erzeuger und Verbraucher nicht gleichzeitig etwas in den Puffer eintragen und<br />

aus ihm entnehmen können; sie greifen wechselseitig ausgeschlossen zu.<br />

3.5.2 Definition: Wechselseitiger Ausschluss<br />

Gegeben sei ein Petri-Netz (S, T, F) und eine Anfangsmarkierung M0. Wenn<br />

zwei Transitionen t1, t2 T wechselseitig ausgeschlossen sind, dann ist keine<br />

Markierung M' erreichbar, so dass t1 und t2 unter dieser Markierung gleichzeitig<br />

transaktionsbereit sind. Wir sagen, dass Transitionen, die wechselseitig<br />

ausgeschlossen auszuführen sind, kritische Abschnitte (engl critical section,<br />

critical region) eines Systemablaufs modellieren.<br />

¯ Beispiel: gemeinsame Daten<br />

Der Zugriff auf gemeinsame Ressourcen, z.B. auf gemeinsame Variable,<br />

muss koordiniert werden. Bei exklusiven Ressourcen wird die Nutzung<br />

sequentialisiert. Die gemeinsame Ressource wird in einem kritischen Bereich<br />

bzgl. der gemeinsamen Ressource benutzt.<br />

98


Schlichter, TU München 3.5. SYNCHRONISATION<br />

3.5.3 Modellierung<br />

Prozess P1:<br />

main () {<br />

.......<br />

region x do<br />

x = x + 1:<br />

end region<br />

........<br />

}<br />

Prozess P2:<br />

main () {<br />

.......<br />

region x do<br />

x = x + 2:<br />

end region<br />

........<br />

}<br />

Modelliert man parallele Einheiten, die kritische Abschnitte besitzen, durch Petri-<br />

Netze, so sind vier Phasen dieser parallelen Aktivitäten von Interesse:<br />

1. Ausführen unkritischer Abschnitte/Transaktionen<br />

2. Betreten eines kritischen Abschnitts<br />

3. Ausführen der Transaktion(en) des kritischen Abschnitts<br />

4. Verlassen des kritischen Abschnitts.<br />

Modellierung jeder Phase durch eine Transition; Koordinierung des wechselseitigen<br />

Ausschluss durch Kontrollstelle s.<br />

t1<br />

Prozess 1<br />

t2<br />

t3<br />

t4<br />

Eintritt<br />

k.A.<br />

s<br />

Eintritt<br />

Austritt Austritt<br />

Prozess 2<br />

t1: Phase 1; unkritische Transition<br />

t2: Phase 2; Eintritt in kritischen Abschnitt<br />

t3: Phase 3; Ausführung des kritischen<br />

Abschnitts<br />

t4: Phase 4; Verlassen des kritischen<br />

Abschnitts<br />

s: Kontrollstelle<br />

¯ Beispiel: Leser-Schreiber-Problem<br />

Betrachten wir als Beispiel ein weiteres klassisches Synchronisationsproblem:<br />

das Leser-Schreiber-Problem. Eine einfache Version des Leser-Schreiber-<br />

Problems ist wie folgt gegeben. Das System umfasst Lese-Aktivitäten, die in<br />

99


Schlichter, TU München 3.5. SYNCHRONISATION<br />

ihrem kritischen Abschnitt lesend auf eine gemeinsame Ressource zugreifen<br />

und Schreib-Aktivitäten, die in ihrem kritischen Abschnitt schreibend auf die<br />

gemeinsame Ressource zugreifen. Wir fordern:<br />

1. Lese-Aktionen im kritischen Abschnitt können parallel stattfinden,<br />

wobei die Anzahl der parallelen Leser begrenzt sei, z.B. auf drei.<br />

2. Lese- und Schreib-Aktionen sind wechselseitig ausgeschlossen.<br />

3. auch Schreib-Aktionen sind untereinander wechselseitig ausgeschlossen.<br />

Die Abbildung zeigt eine mögliche Modellierung mittels eines Petri-Netzes mit<br />

drei Lesern und drei Schreibern. Die Anfangsmarkierung der Stelle s beschreibt<br />

die Anzahl der Leser, die maximal parallel im kritischen Abschnitt arbeiten<br />

dürfen. Will ein Schreiber den kritischen Abschnitt betreten, so müssen<br />

alle drei Marken auf s liegen (kein Leser im kritischen Abschnitt). Durch<br />

die Kantengewichtung, werden beim Betreten des kritischen Abschnitts alle<br />

Marken von s durch den Schreiber konsumiert. Beim Verlassen des kritischen<br />

Abschnitts, werden wieder drei Marken produziert, also allen Lesern wieder ein<br />

Zugriff ermöglicht.<br />

Leser Schreiber<br />

Eintritt<br />

Eintritt<br />

k.A. k.A.<br />

s<br />

3<br />

3<br />

Austritt Austritt<br />

3.5.4 Synchronisierungskonzepte<br />

Ziel: Einführung wichtiger Realisierungskonzepte zur Synchronisierung paralleler<br />

Abläufe. Dazu Konkretisierung des Prozessbegriffs. Um die modellierten<br />

100


Schlichter, TU München 3.5. SYNCHRONISATION<br />

Eigenschaften eines System zu realisieren, benötigt man Konzepte zur Formulierung<br />

paralleler Abläufe. Auf der programmiersprachlichen Ebene sind dies<br />

Sprachkonstrukte, wie die Java-Threads oder die Ada-Tasks. Für das Folgende<br />

benötigen wir einen Prozessbegriff, der den abstrakten Prozessbegriff (siehe<br />

Seite 68) zunächst nur so konkretisiert, dass wir damit erste wichtige Konzepte<br />

zur Realisierung von Abhängigkeiten zwischen parallelen Aktivitäten einführen<br />

können. Dies ist ein erster Schritt in die Richtung auf einen Prozess, wie er auf<br />

der Betriebssystemebene benötigt wird. Auf die weitere Konkretisierung eines<br />

Prozesses als Betriebssystem-Verwaltungseinheit zusammen mit den Maßnahmen<br />

zur seiner Verwaltung gehen wir in den folgenden Abschnitten ein.<br />

Prozess - Konkretisierung<br />

Ein Prozess ist ein eindeutig identifizierbarer Ablauf eines Programms in<br />

einem Rechensystem. Der Ablauf ist bestimmt durch die Befehle und Daten<br />

des Programms. Ein Prozess kann unterschiedliche Zustände besitzen. Wir<br />

unterscheiden die Zustände erzeugt, rechnend, rechenwillig, wartend, terminiert.<br />

Die Zustände eines Prozesses und Beispiele für Aktionen, die Zustandsübergänge<br />

zur Folge haben, sind in der Abbildung angegeben.<br />

fork start<br />

erzeugt<br />

terminiert<br />

end<br />

kill<br />

rechnend<br />

CPU<br />

Zuteilung<br />

E/A-Auftrag<br />

CPU-Entzug<br />

rechenwillig<br />

wartend<br />

E/A-<br />

Auftrag<br />

beendet<br />

Zur Verwaltung eines Prozesses wird eine Datenstruktur benötigt, die alle Information,<br />

die einen Prozess charakterisiert, beinhaltet. Dies ist der Prozess-<br />

Kontext (Prozess-Deskriptor), der auf dieser Konkretisierungsebene den eindeutigen<br />

Prozessnamen und die Prozesszustände umfasst und später noch erweitert<br />

wird (z.B. Priorität, Registerinhalte). Dazu gibt es in der Modellmaschine<br />

das Programmstatuswort PSW, das alle relevanten Kontextinformation eines Programmablaufes<br />

speichert.<br />

101<br />

kill


Schlichter, TU München 3.5. SYNCHRONISATION<br />

Konzepte für wechselseitigen Ausschluss<br />

Die Netz-Modellierung hat bereits gezeigt, dass man zur Synchronisation von<br />

Prozessen spezifische Kontrollkomponenten benötigt (z.B. zusätzliche Stellen<br />

im Petri-Netz, oder Kapazitätsbeschränkungen, die implizit durch die abstrakte<br />

Kontrollkomponente, die die Transitionsbereitschaft von Transitionen prüft,<br />

kontrolliert werden). Weiterhin hat die Modellierung gezeigt, dass durch<br />

die Synchronisationsmaßnahmen, die ja im wesentlichen durch absichtlich<br />

herbeigeführte Konflikte modelliert wurden, ggf. unfaire Abläufe auftreten, die in<br />

einem realisierten System natürlich unerwünscht sind. Das heißt, wir benötigen<br />

geeignete Konzepte, durch die diese Kontrollaufgaben wahrgenommen werden<br />

und ein unfaires Verhalten vermieden wird.<br />

¯ Anforderungen<br />

Folgende Anforderungen sind an eine Realisierung des wechselseitigen<br />

Ausschlusses (w.A.) zu stellen:<br />

– Die kritischen Abschnitte der Prozesse sind wechselseitig auszuschließen.<br />

– Eine Realisierung des w.A. darf nicht von einer Annahme über die<br />

Reihenfolge, in der die Prozesse ihre kritischen Abschnitte ausführen,<br />

abhängen.<br />

– Eine Realisierung des w.A. darf nicht von Annahmen über die Ausführungszeit<br />

der Prozesse abhängen.<br />

– Unter der Annahme, dass Prozesse nach endlicher Zeit ihre kritischen<br />

Abschnitte wieder verlassen, muss gelten, dass kein Prozess einen anderen<br />

Prozess unendlich lange daran hindern darf, seinen kritischen Abschnitt<br />

auszuführen.<br />

¯ Jede Realisierung des w.A. benötigt eine Basis, mit festgelegten atomaren,<br />

d.h. nicht teilbaren Operationen. Diese unteilbaren Basisoperationen sind<br />

von Hard- und/oder Software zur Verfügung zu stellen. Informell: mit einer<br />

atomaren Operation kann überprüft werden, ob der kritische Abschnitt frei ist;<br />

falls ja kann er sofort betreten werden (und der kritische Abschnitt damit belegt<br />

werden). Falls die Abfrage und das Betreten nicht atomar sind, können mehrere<br />

zeit-verzahnte Abfrage stattfinden, und gegebenenfalls mehrere Prozesse den<br />

kritischen Abschnitt betreten.<br />

¯ Unterbrechungssperre<br />

Der Ablauf des Prozesses darf nicht unterbrochen werden.<br />

102


Schlichter, TU München 3.5. SYNCHRONISATION<br />

– In Ein-Prozessorsystemen kann es ausreichend sein, mit Enable und Disable<br />

Interrupt Operationen dafür zu sorgen, dass der Prozess, der einen kritischen<br />

Abschnitt ausführt, dabei nicht unterbrochen wird. Dies ist nur eine<br />

sinnvolle Vorgehensweise, wenn die kritischen Abschnitte kurz sind, da<br />

ansonsten die Systemantwortzeiten sehr hoch werden und u.U. E/A-Aufträge<br />

nicht rechtzeitig behandelt werden. Atomarität durch Unterbrechungssperre<br />

funktioniert nicht unbedingt bei Mehrprozessormaschinen.<br />

– Realisierung mit Unterbrechungssperre ist nützlich für den Betriebssystemkern,<br />

aber sollte nicht für allgemeine Benutzerprogramme zur Verfügung stehen.<br />

Maschine 'hängt', wenn Benutzerprogramm den kritischen Abschnitt<br />

nicht mehr verlässt.<br />

¯ Test-and-Set Operationen<br />

Test-and-Set Operationen (Test-And-Set-Lock, TSL) erlauben auf Hardware-<br />

Ebene (Maschinenbefehl) das Lesen und Schreiben einer Speicherzelle als<br />

atomare Operation.<br />

– Semantik eines Test-and-Set-Befehls<br />

Die Instruktion liest den Inhalt eines Speicherwortes in ein Register und<br />

schreibt einen Wert ungleich Null an die Adresse des Wortes. Diese beiden<br />

Operationen werden als atomare, unteilbare Sequenz ausgeführt. Durch<br />

Hardware bereitgestellte atomare Lese- und Schreiboperationen findet man<br />

z.B. in Sun SPARC mit Befehl: compare and swap; entsprechendes gibt es<br />

bei Motorola, Intel 80x86, Mips R4000.<br />

£ Problem: wie Atomarität gewährleistet?<br />

£ Lösung: Die CPU, die die TSL-Instruktion ausführt, blockiert den<br />

Speicherbus, um andere CPU's (Multi-Prozessorumgebung) daran zu<br />

hindern, auf die Speichereinheit zuzugreifen.<br />

– Atomare MI-Befehle<br />

Die Modellmaschine MI unterstützt die beiden atomaren Befehle JBSSI<br />

("Jump on bit set and set interlocked") und JBCCI ("Jump on bit cleared<br />

and clear interlocked")<br />

£ Bitfeld<br />

Ein Bitfeld ist eine lückenlose Folge von bits, die über Byte-Grenzen<br />

hinweg gehen kann. Die maximale Länge S eines Bitfelds in MI ist 32<br />

bit, d.h. S liegt zwischen 0 .. 32. Die Kennzeichnung eines Bitfeldes B(P,<br />

S, A) erfolgt durch drei Parameter:<br />

103


Schlichter, TU München 3.5. SYNCHRONISATION<br />

A: Adresse der Speicherzelle<br />

P: Adresse eines Bit (Bitnummer) relativ zum Bit b0 im Byte mit der<br />

Adresse A; P kann auch negativ sein !<br />

S: Länge des Bitfeldes, 0 S 32.<br />

£ JBSSI a1, a2, a3<br />

Æ Es wird das Bitfeld B(S[a1], 1, a2) angesprochen. Dieses umfasst genau<br />

ein Bit b. Unteilbare Ausführung von<br />

ØÑÔ ÙÖ ØÐ ÒÒÞ ÒØ× Ø <br />

Ö ÙÖ ØÐ ÒÒÞ ÒØ× Ø <br />

ØÑÔ ß È <br />

PC ist hier der Befehlszähler; das Programm wird an der Adresse a3<br />

fortgesetzt, falls der Wert des Bitfeldes 1 war. Andernfalls setze mit<br />

dem nachfolgenden Befehl fort.<br />

£ JBCCI a1, a2, a3<br />

Æ Es wird das Bitfeld B(S[a1], 1, a2) angesprochen. Dieses umfasst genau<br />

ein Bit b. Unteilbare Ausführung von<br />

ØÑÔ ÙÖ ØÐ ÒÒÞ ÒØ× Ø <br />

Ö ÙÖ ØÐ ÒÒÞ ÒØ× Ø <br />

ØÑÔ ß È <br />

¯ Dienste mit passivem Warten<br />

Unterscheidung zwischen<br />

aktivem Warten: Prozess muss periodisch selber prüfen, ob die Voraussetzungen<br />

zum Weiterarbeiten erfüllt sind.<br />

passivem Warten: Prozess wird in Warte-Zustand versetzt und aufgeweckt,<br />

wenn das Ereignis, auf das er wartet, eingetreten ist.<br />

Aktives Warten hat den Nachteil, dass für andere Prozesse nutzbare CPU-<br />

Zyklen durch das wiederholte Anfragen, ob die Voraussetzungen zum<br />

Weiterarbeiten erfüllt sind, nutzlos verschwendet werden. Nachfolgend werden<br />

einige Dienste für passives Warten kurz aufgelistet.<br />

– Methoden oder Dienste, so dass unter Mithilfe des Betriebssystems ein<br />

Prozess in den Zustand wartend übergeführt wird.<br />

– beim Eintreten eines passenden "Weckereignisses" wird der Prozess<br />

vom Betriebssystem vom Zustand wartend in den Zustand rechenbereit<br />

übergeführt.<br />

– Beispiel: Java wait und notify.<br />

Wait: passives Warten auf das Eintreffen einer Bedingung und<br />

atomar gleichzeitig Freigabe der umfassenden Sperre einer synchronized<br />

Methode. Wait/notify nur innerhalb von synchronized nutzbar!<br />

Notify: Benachrichtigen eines wartenden Threads.<br />

104


Schlichter, TU München 3.5. SYNCHRONISATION<br />

Aber: in Java nicht möglich anzugeben, auf WAS ein Thread warten soll<br />

bzw. WELCHE Bedingung eingetreten ist. Nach dem Aufwecken muss<br />

der Thread also noch einmal explizit prüfen, ob der Weckruf den Thread<br />

wirklich betrifft. In Unix gibt es die Aufrufe Sleep and Wakeup; dies<br />

sind Betriebssystemaufrufe, mit denen der Aufrufer blockiert und wieder<br />

rechenbereit gesetzt werden kann.<br />

¯ Semaphor-Konzept<br />

Das Semaphor-Konzept ermöglicht die Realisierung des w.A. auf einem<br />

höheren Abstraktionslevel als die bereits angesprochenen Hardwareoperationen.<br />

Zur Realisierung wird aber auf diese wieder zurückgegriffen. Realisierung<br />

von Semaphoren mit aktivem und passivem Warten möglich. Ein weiterer Synchronisationsansatz<br />

sind Monitore. Darunter versteht man einen abstrakten Datentyp,<br />

dessen Operationen konzeptuell wechselseitig ausgeschlossen sind.<br />

¯ Monitor-Konzept<br />

Das Monitor-Konzept basiert auf der Idee, die in einem kritischen Bereich<br />

bearbeiteten Daten zusammen mit den darauf definierten Zugriffsalgorithmen<br />

in einer sprachlichen Einheit - dem Monitor - zusammenzufassen. Prozesse<br />

können zwar jederzeit die Methoden (Prozeduren) eines Monitors aufrufen,<br />

jedoch können sie nicht direkt auf die internen Daten eines Monitors zugreifen.<br />

Zu jedem Augenblick kann nur ein Prozess innerhalb des Monitors aktiv sein.<br />

Der erfolgreiche Aufruf einer Monitorprozedur ist gleichbedeutend mit der<br />

Sperre des Monitors, die bis zum Verlassen der Monitorprozedur bestehen<br />

bleibt. Die Vorteile des Monitor-Konzepts gegenüber den Semaphoren ist a) die<br />

gemeinsamen Daten werden in der Programmstruktur der beteiligten Prozesse<br />

explizit sichtbar gemacht, und b) Monitore kapseln alle relevanten Daten<br />

und Algorithmen des kritischen Bereichs. Innerhalb eines Monitors können<br />

Condition-Variable definiert werden, die anwendungsspezifische Bedingungen<br />

formulieren. Jede Condition-Variable steht für eine Bedingung, die für die<br />

Fortsetzung eines Prozesses in einer Monitorprozedur erfüllt sein. Falls die<br />

Bedingung nicht erfüllt ist, wird die wait-Operation auf dieser Condition-<br />

Variable ausgeführt. Mit sleep können Prozesse wieder aufgeweckt werden.<br />

3.5.5 Semaphore<br />

Semaphore wurden 1968 von Dijkstra eingeführt. Ein Semaphor (Signalmast)<br />

ist eine ganzzahlige Koordinierungsvariable s, auf der nur die drei vordefinierten<br />

Operationen (Methoden) zulässig sind:<br />

105


Schlichter, TU München 3.5. SYNCHRONISATION<br />

Initialisierung,<br />

Prolog P (kommt von protekt),<br />

Epilog V (kommt von vrej).<br />

Operationen<br />

Die Operationen P und V sind atomar; sie sind unteilbar und sie werden<br />

wechselseitig ausgeschlossen ausgeführt.<br />

Sei s die Koordinierungsvariable, dann sind die P und V Operationen wie<br />

nachfolgend definiert.<br />

Die Operation müssen mit Hilfe von Systemdiensten so realisiert werden, dass<br />

sie wechselseitig ausgeschlossen ausgeführt werden. Vorsicht: hier gibt es keine<br />

ganz einheitliche Definition in der Literatur für die beiden Operationen.<br />

¯ Informelle Charakterisierung<br />

ÔÙÐ ÚÓ È ÒØ × ß<br />

× × <br />

× ß ÈÖÓÞ×× Ò ÅÒ Ö ÞÐ ×<br />

ÛÖØÒÒ ÈÖÓÞ×× ÒÖÒ <br />

<br />

ÔÙÐ ÚÓ Î ÒØ × ß<br />

× × <br />

× ß Ö ÒÙ ÒÒ Ö ÞÐ × ÛÖØÒÒ<br />

ÈÖÓÞ×× Ò Ò Ù×ØÒ Ö ÒÛÐÐ Ö <br />

<br />

s ist mit einem ganzzahligen Wert vorbesetzt, z.B. s = 1. Falls s mit einem Wert<br />

größer 1 vorbesetzt ist, bedeutet dies die Anzahl der Prozesse, die gleichzeitig<br />

im kritischen Bereich erlaubt sind.<br />

¯ Binäres Semaphor: die Kontrollvariable s nimmt nur boolesche Werte an.<br />

Einsatz von Semaphoren<br />

Notation: Zur Vereinfachung gehen wir im Folgenden von einem vordefinierten<br />

Typ ×ÑÔÓÖ ÒØ × aus, der die P und V Operationen als vordefinierte,<br />

atomare Methoden anbietet. Semaphor-Objekte werden als Instanzen bezüglich<br />

des Typs ×ÑÔÓÖ erzeugt, wobei bei der Instantiierung das Semaphor mit dem<br />

Parameter s initialisiert wird.<br />

106


Schlichter, TU München 3.5. SYNCHRONISATION<br />

¯ Zugang zu kritischen Abschnitten<br />

Realisierung der kritischen Abschnitte von Prozessen, in denen auf eine<br />

exklusiv benutzbare Ressource X zugegriffen wird:<br />

1. Definition eines Semaphor-Objekts wa: semaphor(1), d.h. Initialisierung der<br />

Kontrollvariable des Semaphor-Objekts wa mit 1.<br />

2. Klammern der kritischen Abschnitte, in denen auf die Ressource X<br />

zugegriffen wird, mit P und V Operationen:<br />

wa.P<br />

Code mit Zugriffen auf X<br />

wa.V<br />

¯ Die Anforderungen an Lösungen des wechselseitigen Ausschlusses sind mit<br />

dem Semaphor-Konzept aus folgenden Gründen erfüllt:<br />

– Wechselseitiger Ausschluss für alle kritischen Abschnitte. Aufgrund der<br />

Initialisierung der Koordinierungsvariablen mit 1 kann sich stets nur ein<br />

Prozess in einem kritischen Abschnitt befinden.<br />

– keine Reihenfolge-Annahmen. Annahmen über die Ausführungsreihenfolge<br />

der kritischen Abschnitte gehen nicht ein.<br />

– keine Ausführungszeit-Annahmen. Es werden keine Annahmen über die<br />

Ausführungszeiten der Prozesse gemacht.<br />

– kein Verhungern. Hier muss bei der Realisierung des Semaphors eine<br />

faire Strategie, z.B. FIFO (First-In-First-Out), zum Einsatz kommen. Wenn<br />

die blockierten Prozesse aus dem Warteraum nach FIFO entnommen<br />

werden und jeder kritische Abschnitt mit der P- und der V-Operation des<br />

Semaphors geklammert ist, wird jeder blockierte Prozess nach endlicher Zeit<br />

entblockiert und kann somit seinen kritischen Abschnitt ausführen.<br />

¯ Semaphor in MI<br />

MI-Realisierung eines binären Semaphors mit aktivem Warten. Es ist auch<br />

möglich Semaphore in MI auf der Basis des passiven Wartens zu realisieren.<br />

Für ein binäres Semaphor gilt, dass die Semaphor-Variable s nur die Werte 0<br />

oder 1 annehmen kann.<br />

Wirkung von s.P: if s == 1 {s = 0} else {warten bis s.V ausgeführt wird}<br />

Wirkung von s.V: s = 1; falls ein Prozess wartet, dann aufwecken.<br />

Für die Realisierung gehen wir davon aus, dass beim Aufruf von s.P und s.V<br />

die Adresse von s auf den Stack geschrieben wird.<br />

107


Schlichter, TU München 3.5. SYNCHRONISATION<br />

È ÂÁ Á ËÈ <br />

ÊÌ ÙÒ ÞÙÑ ÖØ× Ò Ö <br />

Î ÅÇÎ Ï Á ËÈ<br />

ÊÌ<br />

JBCCI steht für "Jump on Bit Cleared and Cleared Interlocked". Das Bitfeld ist<br />

gegeben durch (31, 1, !(4+!SP)). Die Länge des Bitfeldes ist gleich 1; betrachtet<br />

wird das Bit 31 der durch !(4+!SP) spezifizierten Speicherzellen (4 Bytes).<br />

Falls das durch das Bitfeld spezifizierte Bit gleich 0 ist, erfolgt ein Sprung zur<br />

Adresse a.<br />

Beispiel Erzeuger-Verbraucher<br />

Im Modellierungsteil wurde das Erzeuger-Verbraucher-Problem (siehe<br />

Seite 83) bereits kurz vorgestellt.<br />

Der Erzeuger-Prozess E erzeugt Datenelemente und schreibt sie in einen<br />

Puffer W.<br />

Der Verbraucher-Prozess V liest Datenelemente aus dem Puffer und<br />

verarbeitet sie.<br />

Der Zugriff der beiden Prozesse auf den Puffer ist zu synchronisieren.<br />

Lösung dieses Problems mittels Semaphor.<br />

¯ Variante 1<br />

Zugriff auf Puffer W erfolgt durch Semaphor wa: semaphor(1); sowohl der<br />

Erzeuger-Prozess E als auch der Verbraucher-Prozess V rufen vor jedem Zugriff<br />

auf den Puffer W die entsprechenden Operationen des Semaphors wa auf.<br />

Erzeuger E:<br />

while (true) {<br />

produziere<br />

wa.P<br />

schreibe nach W<br />

wa.V<br />

}<br />

Verbraucher V:<br />

while (true) {<br />

wa.P<br />

entnimm aus W, falls Element da; sonst warte<br />

wa.V<br />

verarbeite<br />

}<br />

Problem: es kann eine Verklemmung auftreten, wenn der Verbraucher wa.P<br />

ausführt und warten muss, weil der Puffer kein Element enthält. Andererseits<br />

kann der Erzeuger den Puffer nicht betreten, da bereits der Verbraucher den<br />

Puffer exklusiv belegt hat.<br />

¯ Variante 2<br />

108


Schlichter, TU München 3.5. SYNCHRONISATION<br />

Einführen eines zusätzlichen Semaphors voll: semaphor(0), das die Datenelemente<br />

im Puffer zählt:<br />

Erzeuger E:<br />

while (true) {<br />

produziere<br />

wa.P<br />

schreibe nach W<br />

wa.V<br />

voll.V<br />

}<br />

Verbraucher V:<br />

while (true) {<br />

voll.P<br />

wa.P<br />

entnimm aus W<br />

wa.V<br />

verarbeite<br />

}<br />

Für den Erzeuger ergibt sich natürlich ein analoges Problem, falls der Puffer W<br />

nur eine beschränkte Kapazität besitzt. Eine Abhilfe kann analog wieder durch<br />

die Einführung eines weiteren Semaphors "leer" erreicht werden. Dieses stellt<br />

sicher, dass der Erzeuger den Puffer nicht betritt, wenn der Puffer bereits voll<br />

ist.<br />

¯ Variante 3<br />

Einführen eines zusätzlichen Semaphors leer: semaphor(n), das die Anzahl der<br />

freien Elemente im Puffer zählt:<br />

wa.semaphor(1); //kontrolliert den Zugang zum kritischen Bereich<br />

voll.semaphor(0); //zählt die Anzahl der Einheiten im Puffer<br />

leer.semaphor(n), //zählt die Anzahl der freien Pufferplätze<br />

Erzeuger E:<br />

while (true) {<br />

produziere Einheit;<br />

leer.P;<br />

wa.P;<br />

schreibe Einheit nach W;<br />

wa.V;<br />

voll.V;<br />

}<br />

Verbraucher V:<br />

while (true) {<br />

voll.P;<br />

wa.P;<br />

entnimm Einheit aus W<br />

wa.V<br />

leer.V;<br />

verarbeiteEinheit;<br />

}<br />

Darf die Reihenfolge der P-Operationen für die Semaphore leer, voll, wa<br />

beim Erzeuger bzw. beim Verbraucher vertauscht werden, ohne dass sich<br />

Ablaufprobleme ergeben?<br />

109


Schlichter, TU München 3.5. SYNCHRONISATION<br />

Beispiel Philosophenproblem<br />

Zu den klassischen Synchronisationsproblemen zählt das Problem der speisenden<br />

Philosophen ("Dining Philosophers"). In einem Elfenbeinturm leben fünf<br />

Philosophen. Der Tageszyklus eines jeden Philosophen besteht abwechselnd aus<br />

Essen und Denken. Die fünf Philosophen essen an einem runden Tisch, auf dem in<br />

der Mitte eine Schüssel voller Spaghetti steht. Jeder Philosoph hat seinen festen<br />

Platz an dem Tisch und zwischen zwei Plätzen liegt genau ein Stäbchen. Das<br />

Problem der Philosophen besteht nun darin, dass die Spaghetti nur mit genau<br />

zwei Stäbchen zu essen sind. Darüber hinaus darf jeder Philosoph nur das direkt<br />

rechts und das direkt links neben ihm liegende Stäbchen zum Essen benutzen. Das<br />

bedeutet, dass zwei benachbarte Philosophen nicht gleichzeitig essen können.<br />

¯ Realisierung mit Semaphoren<br />

4<br />

3<br />

3<br />

4<br />

0<br />

2<br />

– Variante 1<br />

Für eine Lösung des Philosophenproblems seien die folgenden 5 Semaphore<br />

definiert: stab_0, stab_1, ...., stab_4, wobei jedes der 5 Semaphore mit 1<br />

initialisiert ist. Jeder Philosoph j, mit j {0,...,4}, führe den folgenden<br />

Algorithmus aus:<br />

ÔÐÓ×ÓÔ<br />

ÛÐ ØÖÙ ß<br />

ÒÒ<br />

×Ø È ÑØ <br />

×Ø È<br />

××Ò<br />

ÑØ ÑÓ <br />

×Ø Î ÑØ <br />

×Ø Î ÑØ ÑÓ <br />

<br />

Der angegebene Algorithmus liefert keine korrekte Lösung des wechselseitigen<br />

Ausschlusses! Wenn alle fünf Philosophen gleichzeitig die er-<br />

0<br />

110<br />

1<br />

2<br />

1


Schlichter, TU München 3.5. SYNCHRONISATION<br />

ste P-Operation (stab_i.P mit i = j) ausführen, d.h. alle gleichzeitig ihr<br />

linkes Stäbchen nehmen, folgt daraus eine Verklemmungs-Situation, da kein<br />

Philosoph das zweite Stäbchen nehmen kann. Bei Ausführung der zweiten<br />

P-Operation stab_i.P; mit i=j+1 mod 5 werden alle Philosophen blockiert.<br />

Die Philosophen verhungern somit.<br />

– Variante 2<br />

Nur vier Philosophen dürfen gleichzeitig zu ihrem linken Stäbchen<br />

greifen. Dies wird durch Einführung eines weiteren Semaphors Ø× <br />

×ÑÔÓÖ , das mit 4 initialisiert wird, erreicht. Der "Anweisungsteil"<br />

jedes Philosophen wird zusätzlich mit Ø× È und Ø× Î geklammert.<br />

Dadurch ist gewährleistet, dass höchstens vier Philosophen gleichzeitig ihr<br />

linkes Stäbchen nehmen können und somit immer mindestens ein Philosoph<br />

auch sein zweites Stäbchen nehmen und damit essen kann. Es ergibt sich<br />

also folgende Lösung: Jeder Philosoph j, mit j<br />

Algorithmus aus:<br />

ÔÐÓ×ÓÔ<br />

{0,...,4} führt den folgenden<br />

ÛÐ ØÖÙ ß<br />

ÒÒ<br />

Ø× È<br />

×Ø È ÑØ <br />

×Ø È<br />

××Ò<br />

ÑØ ÑÓ <br />

×Ø Î ÑØ <br />

×Ø Î<br />

Ø× Î<br />

ÑØ ÑÓ <br />

<br />

Ein weiterer wichtiger Aspekt ist die Reihenfolge bei der Ausführung<br />

von P Operation, falls mehrere Semaphore belegt werden müssen.<br />

Eine unterschiedliche Reihenfolge der P-Operationen bei den beteiligten<br />

Prozessen kann leicht zu einer Verklemmung führen.<br />

Animation Semaphor<br />

siehe online Version<br />

3.5.6 Synchronisierung von Java Threads<br />

Java unterstützt synchronisierte Methoden.<br />

ÔÙÐ ×ÝÒ ÖÓÒÞ ÚÓ ÑØÓÒÑ ß <br />

Eine synchronisierte Methode kann nur exklusiv von einem Java Thread betreten<br />

werden. Andere Threads können die synchronisierte Methode erst dann betreten,<br />

111


Schlichter, TU München 3.6. VERKLEMMUNGEN<br />

wenn der erste Java Thread die Methode wieder verlässt. Einer der wartenden<br />

Threads wird aktiviert.<br />

Java Monitor<br />

Ein Monitor ist ein Java-Objekt, das synchronisierte Methoden enthält.<br />

¯ Ein Monitor stellt sicher, dass nur ein Thread zur Zeit in einer der<br />

synchronisierten Methoden sein kann. Bei Aufruf einer synchronisierte<br />

Methode wird das Objekt gesperrt.<br />

¯ Während das Objekt gesperrt ist, können keine anderen synchronisierten<br />

Methoden des Objekts aufgerufen werden. Andere Threads müssen warten,<br />

bis der erste Thread die synchronisierte Methode wieder verlässt, und damit die<br />

Sperre freigibt.<br />

¯ Kritische Abschnitte können in Java als Objekte mit den zugehörigen<br />

synchronisierten Methoden spezifiziert werden. Synchronisierte Methoden<br />

können je nach der verwendeten Java Virtual Machine sehr aufwendig und<br />

langsam sein. Weiterhin ist zu beachten, dass zwar innerhalb eines Monitors<br />

eine synchronisierte Methode andere synchronisierte Methoden blockiert, nicht<br />

jedoch unsynchronisierte Methoden. Dies kann u.U. zu Problemen führen.<br />

3.6 Verklemmungen<br />

Mit Verklemmung (engl. deadlock) bezeichnet man einen Zustand, in dem die<br />

beteiligten Prozesse wechselseitig auf den Eintritt von Bedingungen warten, die<br />

nur durch andere Prozesse in dieser Gruppe selbst hergestellt werden können.<br />

Verklemmungen können durch die gemeinsame Verwendung von Ressourcen<br />

(synonym verwenden wir auch den Begriff Betriebsmittel), wie z.B. CPU, Arbeitsspeicher,<br />

E/A-Geräte, Dateien auftreten. Der Austausch von Information<br />

über gemeinsame Speicherbereiche ist eine häufige Situation (speicherbasierte<br />

Prozessinteraktion), die bei unkorrekter Verwendung von Synchronisationsoperationen<br />

(z.B. P und V bei Semaphoren) leicht zu Verklemmungen führen<br />

kann; siehe die Variante 1 (siehe Seite 108) des Erzeuger-Verbraucher Lösungsansatzes.<br />

Dieser Abschnitt skizziert nur die Ansätze zur Erkennung, Vermeidung<br />

und Verhinderung von Verklemmungen. Ein ausführliche Behandlung<br />

dieser Thematik erfolgt in der Vorlesung Betriebssysteme des Hauptstudiums. In<br />

vielen Systemen wird eine 'Vogel-Strauß'-Politik in bezug auf die Deadlockproblematik<br />

verfolgt, d.h. es werden keine Maßnahmen eingesetzt, sondern es wird<br />

112


Schlichter, TU München 3.6. VERKLEMMUNGEN<br />

gehofft, dass alles gut geht. In Unix wird diese Philosophie z.B. bei der Verwaltung<br />

der Prozesstabelle verfolgt.<br />

3.6.1 Allgemeines<br />

Es lässt sich zeigen, dass die folgenden Bedingungen notwendig und hinreichend<br />

dafür sind, dass eine Verklemmung auftreten kann.<br />

1. Die gemeinsam benutzbaren Ressourcen können nicht parallel genutzt werden,<br />

d.h. sie sind nur exklusiv benutzbar.<br />

2. Die zugeteilten/belegten Ressourcen können nicht entzogen werden, d.h. die<br />

Nutzung ist nicht unterbrechbar.<br />

3. Prozesse belegen die schon zugeteilten Ressourcen auch dann, wenn sie auf<br />

die Zuteilung weiterer Ressourcen warten, d.h. wenn sie weitere Ressourcen<br />

anfordern.<br />

4. Es gibt eine zyklische Kette von Prozessen, von denen jeder mindestens eine<br />

Ressource belegt, die der nächste Prozess in der Kette benötigt, d.h. zirkuläre<br />

Wartebedingung.<br />

3.6.2 Belegungs-Anforderungsgraph<br />

Die Zuteilung/Belegung und Anforderung von Ressourcen kann man sich an<br />

einem Graphen, dem Belegungs-Anforderungsgraph, veranschaulichen. Die<br />

Knoten sind die Prozesse und Ressourcen, die Kanten spiegeln Belegungen und<br />

Anforderungen wider.<br />

¯ Beispiel<br />

Seien P = {P1, ... , Pn} Prozesse und R= {R1, ... , Rm} Ressourcen, z.B. n = 3<br />

und m = 4. Beispiel eines Belegungs/Anforderungsgraphen.<br />

fordert<br />

P1 R1<br />

R2<br />

belegt<br />

fordert<br />

P2<br />

belegt<br />

fordert<br />

113<br />

P3<br />

R3<br />

belegt<br />

belegt<br />

R4


Schlichter, TU München 3.6. VERKLEMMUNGEN<br />

P1 und P2 warten gegenseitig aufeinander. P1 wartet auf R1, die durch P2<br />

belegt ist, und P2 wartet auf R2, die durch P1 belegt ist.<br />

3.6.3 Verklemmungs-Erkennung<br />

In der Praxis häufig angewendete Strategie: Verklemmungen in Kauf nehmen,<br />

sie erkennen und beseitigen. Man versucht eine Verklemmung festzustellen<br />

und sie, sollte sie eingetreten sein, zu beseitigen. Indiz für Verklemmungen,<br />

z.B. angeforderte Ressource ist nach einer gewissen Zeit immer noch nicht<br />

zugewiesen.<br />

¯ Erkennungs-Algorithmus<br />

Ansatz 1: Suche nach Zyklen im Belegungs/Anforderungsgraph.<br />

Ansatz 2: Prüfen, ob es eine Reihenfolge für die Ausführung der Prozesse gibt,<br />

so dass alle Prozesse terminieren können.<br />

¯ Vorgehen für Ansatz 2<br />

1. Starte mit Prozessmenge P, die alle Prozesse enthält,<br />

2. suche Prozess p aus P, dessen zusätzliche Anforderungen im aktuellen<br />

Zustand erfüllbar sind,<br />

3. falls gefunden, simuliere, dass p seine belegten Ressourcen wieder<br />

freigibt,<br />

4. entferne p aus P und gehe zu 2<br />

5. falls kein Prozess mehr in P, dann terminiert Suche: keine Verklemmung,<br />

6. falls P Ø und in Schritt 2 kein Prozess mehr gefunden wird, dessen<br />

Anforderungen erfüllbar sind, dann terminiert die Suche; P enthält die<br />

Menge der verklemmten Prozesse.<br />

¯ Auflösung einer Verklemmung in der Regel durch Abbruch einzelner<br />

Prozesse. Dies erfordert in der Regel einen manuellen Eingriff bei der<br />

Auswahl der abzubrechenden Prozesse. Problem: Prozesse müssen erneut<br />

ausgeführt werden, bei Nicht-Determinismus ggf. anderes Verhalten der neuen<br />

Prozessabläufe.<br />

3.6.4 Verklemmungs-Vermeidung<br />

Die Vermeidungsverfahren beruhen darauf, dass man durch die Festlegung von<br />

Regeln dafür sorgt, dass mindestens eine der für das Auftreten von Deadlocks<br />

notwendigen Bedingungen nicht erfüllt ist. Aber: solche Regeln lassen sich nicht<br />

für jedes Verklemmungsproblem finden. Deshalb wird meist ein allgemeinerer<br />

Algorithmus gesucht: Verhinderungs-Algorithmus.<br />

114


Schlichter, TU München 3.6. VERKLEMMUNGEN<br />

¯ Festgelegte lineare Reihenfolge<br />

Bedingung "Zyklus tritt auf" in Belegungs-/ Anforderungsgraph darf nicht<br />

erfüllt werden. Dazu wird eine lineare Ordnung über den Ressourcen definiert:<br />

R1 R2 ... Rm.<br />

Die Prozesse dürfen dann Ressourcen nur gemäß dieser Ordnung anfordern,<br />

d.h. ein Prozess, der Ressource Ri belegt, darf nur Ressourcen Rj anfordern,<br />

für die gilt: Rj Ri.<br />

Problem: wie Ordnung festlegen? Daumenregel: wichtige Ressourcen, die<br />

gut ausgelastet genutzt werden sollten, dürfen nicht zulange einem Prozess<br />

zugeordnet werden. Deshalb sollte für eine solche Ressource Rj gelten: Rj<br />

Ri, für unwichtigere Ri.<br />

¯ Andere Möglichkeiten sind:<br />

a) Zuteilung aller benötigten Ressourcen zu einem Zeitpunkt.<br />

b) zwangsweiser Entzug aller belegter Ressourcen, falls eine Ressourcen-<br />

Anforderung nicht erfüllt werden kann. Gerade durch die Virtualisierung<br />

und die Bereitstellung logischer Geräte konnte dieser Ansatz verfolgt<br />

werden. Durch die eingeführte Indirektionsstufe war es möglich, einem<br />

Prozess ohne dessen Wissen physische Ressourcen in kritischen Situationen<br />

zu entziehen und damit eine der 4 notwendigen Bedingungen für das<br />

Entstehen einer Verklemmung außer Kraft zu setzen.<br />

3.6.5 Verklemmungs-Verhinderung<br />

Die Verhinderungsverfahren basieren auf der Idee,<br />

die zukünftigen Betriebsmittelanforderungen von Prozessen zu analysieren<br />

(bzw. diese geeignet abzuschätzen) und<br />

solche Zustände zu verbieten (sie also zu verhindern), die zu Verklemmungen<br />

führen könnten.<br />

Ein Beispiel ist der Bankiers-Algorithmus, der 1965 von Dijkstra entwickelt<br />

wurde.<br />

Veranschaulichung des Algorithmus<br />

Veranschaulichung des Verfahrens anhand eines Bankenszenarios. Das Verfahren<br />

wird im Hauptstudium in der Betriebssystem-Vorlesung ausführlicher behandelt.<br />

115


Schlichter, TU München 3.6. VERKLEMMUNGEN<br />

¯ Ausgangspunkt<br />

Idee: Verwaltung von nur einer Ressourcen-Klasse, nämlich den Bankkrediten.<br />

– Bankier besitzt festen Geldbetrag und verleiht Geld an seine Kunden.<br />

– Alle Kunden sind dem Bankier bekannt, jeder Kunde hat einen eigenen<br />

maximalen Kreditrahmen, der kleiner als die zur Verfügung stehende<br />

Geldmenge des Bankiers ist.<br />

– Bankier hat weniger Geld als die Summe dieser Kreditrahmen.<br />

– Kunden können jederzeit Geld in der Höhe ihres jeweiligen Kreditrahmens<br />

fordern, müssen aber ggf. in Kauf nehmen, dass der Bankier diese Forderung<br />

erst nach endlicher Zeit erfüllt.<br />

¯ Aufgabe des Bankiers<br />

Verleihen des Geldes so, dass jeder Kunde seine Geschäfte in endlicher<br />

Zeit durchführen kann und Kunden möglichst parallel bedient werden. Die<br />

sequentielle Abfolge ist natürlich eine triviale Lösung.<br />

Idee: Reihenfolge für Kreditvergabe finden, so dass selbst bei denkbar<br />

ungünstigsten Kreditforderungen die Durchführung aller Geschäfte<br />

sichergestellt ist.<br />

ungünstigster Fall: alle Kunden fordern Geld bis zu ihrem jeweiligen max.<br />

Kreditrahmen, ohne Kredite zurückzuzahlen.<br />

¯ Grobes Vorgehen<br />

1. falls ein Kunde (Prozess) eine Anforderung hat, die aktuell erfüllbar ist,<br />

so teilt man das Geld (die Ressource) probeweise zu und<br />

2. untersucht für den sich damit ergebenden Zustand, ob jetzt eine<br />

Verklemmung vorliegt, indem<br />

3. für alle anderen Kunden von deren ungünstigsten Anforderungen<br />

ausgegangen wird und<br />

4. ein Erkennungs-Algorithmus ausgeführt wird.<br />

Falls keine Verklemmung auftritt, kann die Zuteilung tatsächlich erfolgen,<br />

anderenfalls könnte bei einer Zuteilung ein Deadlock auftreten (muss aber<br />

nicht), weshalb die Anforderung nicht erfüllt wird.<br />

¯ Beispiel<br />

Ausgangspunkt ist die folgende Situation der vier Kunden A, B, C, D (Einheiten<br />

jeweils in Tausend DM):<br />

116


Schlichter, TU München 3.6. VERKLEMMUNGEN<br />

Kunde aktueller Kredit max. Kreditrahmen<br />

A 1 6<br />

B 1 5<br />

C 1 4<br />

D 4 7<br />

Es seien noch 3 Einheiten (Tausend DM) in der Bank als Kredit verfügbar.<br />

– Annahme: Kunde C fordere eine weitere Einheit als Kredit an. Diese<br />

Anforderung wird probeweise zugeteilt und mündet nicht in einem Deadlock,<br />

da zuerst C (max noch 2 Einheiten bis Kreditrahmen) bedient werden kann.<br />

Wenn C seine Einheiten wieder zurückgezahlt hat, können B oder D und<br />

schließlich A bedient werden.<br />

Probleme bei Verhinderungsverfahren: zukünftige maximale Anforderungen<br />

müssen bekannt sein; anderenfalls nur worst-case Abschätzungen<br />

möglich. Algorithmus ist sehr zeit- und speicherplatzaufwendig. Der<br />

Habermann-Algorithmus ist eine Erweiterung des Verfahrens auf verschiedene<br />

Ressourcen.<br />

117


Kapitel 4<br />

Prozess- und Prozessorverwaltung<br />

Erst die Verfügbarkeit von Betriebssystemen gestattet es einem Anwender, die<br />

Anwendungen einfacher zu organisieren und zu realisieren; Betriebssysteme<br />

machen damit eine Rechenanlage zu einem leistungsfähigen, einsetzbaren<br />

Werkzeug. Unter einem Betriebssystem (im weitesten Sinne) verstehen wir<br />

den Komplex von Programmen, dessen Funktionen die Benutzerschnittstelle des<br />

betreffenden Rechensystems bestimmen. Erst das Betriebssystem schafft die<br />

Schnittstelle für einen bequemen Umgang und Zugriff auf die Funktionen der<br />

Rechenanlage.<br />

4.1 Fragestellungen<br />

Dieser Abschnitt gibt eine kurze Einführung in einige wichtige Verwaltungsaufgaben<br />

eines Betriebssystems:<br />

¯ Verwaltung von Prozessen.<br />

¯ Verwaltung des Prozessors, d.h. Zuteilung der CPU an rechenbereite Prozesse<br />

(Scheduling).<br />

¯ Unterbrechungskonzept. Bei Eintreten von bestimmten Ereignissen kann die<br />

Ausführung von Benutzerprogrammen unterbrochen werden, z.B. Warten auf<br />

Eingabe. Dies ermöglicht den Mehrprogrammbetrieb, und damit eine bessere<br />

Ausnutzung und Auslastung aller Geräte eines Rechensystems.<br />

118


Schlichter, TU München 4.2. BETRIEBSSYSTEM - ÜBERBLICK<br />

4.2 Betriebssystem - Überblick<br />

Ein Betriebssystem realisiert die Schnittstelle zwischen dem Benutzer und der physischen<br />

Rechenanlage. Aus der Sicht des Benutzers entsteht durch ein Betriebssystem<br />

eine virtuelle Maschine. Für einen Benutzer ist es nicht wichtig, ob in<br />

einem Rechensystem Systemfunktionen durch Hardware oder Software realisiert<br />

sind. Ein Betriebssystem realisiert insbesondere eine Benutzerschnittstelle. Der<br />

Entwurf und die Implementierung von Betriebssystemen gehören zu den klassischen<br />

Aufgabenstellungen der Systemprogrammierung. Je nach Art der Hardware<br />

gibt es sehr unterschiedliche Typen von Betriebssystemen. Sie reichen von Betriebssystemen<br />

für Großrechner, über Server-BS bis hin zu PC-Betriebsystemen<br />

und eingebetteten Betriebssystemen (z.B. in einem Palm PDA).<br />

4.2.1 BS-Hauptaufgaben<br />

Ein Betriebssystem (engl. operating system) erfüllt folgende Hauptaufgaben:<br />

¯ Veredeln der Hardware (Virtualisierung).<br />

¯ Steuerung und Kontrolle der Programmausführung. Dazu werden die<br />

beiden Betriebsmittel CPU und Arbeitsspeicher geeignet den Programmen<br />

zugeteilt. Zur Durchführung dieser Aufgabe ist eine Prozessverwaltung (die im<br />

System momentan auszuführenden Programme) und eine Benutzerverwaltung<br />

notwendig.<br />

¯ Verwaltung der Ressourcen (Speicher, CPU, Platten, Netz etc.). Die Benutzung<br />

der Ein-/ Ausgabegeräte sowie des Netzanschlusses erfolgt stets über das<br />

Betriebssystem.<br />

¯ Anbieten von Diensten in Form von Schnittstellen, so dass die Ressourcen<br />

genutzt werden können.<br />

¯ Struktureller Aufbau<br />

119


Schlichter, TU München 4.2. BETRIEBSSYSTEM - ÜBERBLICK<br />

berechtigte<br />

Benutzer<br />

Schnittstelle zur Systemumgebung<br />

System-<br />

Prozesse<br />

Speicher<br />

verwaltung<br />

Scheduler &<br />

Dispatcher<br />

Betriebssystem-Schnittstelle<br />

Prozess<br />

verwaltung<br />

Unterbrechungs-<br />

System<br />

Hardware<br />

Konfiguration<br />

4.2.2 Systemprogrammierung<br />

berechtigte<br />

Benutzer<br />

Benutzer-<br />

Prozesse<br />

Datei<br />

system<br />

EA-<br />

System<br />

zu überprüf.<br />

Benutzer<br />

login<br />

Die <strong>Programmierung</strong> eines Betriebssystems gehört zu dem Bereich der Systemprogrammierung.<br />

¯ Definition<br />

Die Systemprogrammierung befasst sich mit der Darstellung, der Realisierung,<br />

den Eigenschaften und der Konstruktion derjenigen Algorithmen für ein<br />

Rechensystem, die die Bearbeitung und Ausführung von Benutzerprogrammen<br />

unter vorgegebenen Qualitätsgesichtspunkten organisieren, d.h. steuern und<br />

kontrollieren, und zum Teil selbst durchführen.<br />

¯ Qualitätskriterien können z.B. sein:<br />

120<br />

Z<br />

u<br />

g<br />

a<br />

n<br />

g<br />

s<br />

k<br />

o<br />

n<br />

t<br />

r<br />

o<br />

l<br />

l<br />

e


Schlichter, TU München 4.2. BETRIEBSSYSTEM - ÜBERBLICK<br />

– Zuverlässigkeit der durchgeführten Berechnung (Behandlung von Systemcrashs,<br />

Netzausfällen, fehlerhafter Nachrichtenübermittlung etc.).<br />

– Effizienz und Performanz einerseits systemglobal, d.h. es wird versucht,<br />

das System optimal auszulasten, andererseits Auftrags-lokal, z.B. es wird<br />

versucht, zu garantieren, dass eine Auftragsbearbeitung eine festgelegte<br />

Zeitdauer nicht überschreitet.<br />

– Einhaltung von Realzeitanforderungen: zeitkritische Aufträge besitzen z.B.<br />

eine Deadline bis zu der sie ausgeführt sein müssen.<br />

– Durchsetzung von Sicherheitsanforderungen: Schutz der Daten und<br />

Informationen vor unberechtigten Zugriffen und Einsichtnahme.<br />

– Benutzerfreundlichkeit: bequeme Formulierungsmöglichkeit von Benutzeraufträgen.<br />

4.2.3 Betriebssystem-Architektur<br />

In der Praxis findet man einige verschiedene BS-Architekturkonzepte, wobei der<br />

monolithische Ansatz und zunehmend auch der Mikrokern-Ansatz am weitesten<br />

verbreitet sind.<br />

Monolithischer Ansatz<br />

Das Betriebssystem besteht aus einer umfangreichen Menge an Funktionen,<br />

die sich bei Bedarf gegenseitig aufrufen können. Die Funktionen werden in<br />

einem großen BS-Kern zusammengefasst. Der BS-Kern wird durch Aufruf<br />

von Systemdiensten betreten. Der BS-Kern hat i.a. nur wenig Struktur. Als<br />

Grundstruktur kann man von 3 Schichten ausgehen: a) die Hauptprozedur, b)<br />

den Systemfunktionen, die von der Hauptprozedur aufgerufen werden, sowie c)<br />

den Hilfsfunktionen. Unix kann als BS mit einer monolithischen Architektur<br />

betrachtet werden.<br />

121


Schlichter, TU München 4.2. BETRIEBSSYSTEM - ÜBERBLICK<br />

Anwendung<br />

Benutzerprozess<br />

Systemdienste<br />

Hardware<br />

Anwendung<br />

Benutzerprozess<br />

Hilfs<br />

funktionen<br />

Benutzer-Modus<br />

(User Mode)<br />

System-Modus<br />

(Kernel Mode)<br />

¯ komplexe, monolithische Betriebssystem sind sehr schwierig zu warten und<br />

zu erweitern. Es ist oft schwierig nachzuvollziehen, welche Konsequenzen<br />

Änderungen von Systemdiensten bzw. Hilfsfunktionen im Betriebsystem<br />

nach sich ziehen. Dies bezieht sich vor allem auf die Synchronisation von<br />

nebenläufigen Zugriffen und die Nutzung von Ressourcen. Es sind oft viele<br />

Detailkenntnisse des gesamten Betriebssystems notwendig.<br />

¯ Geschichtete Systeme<br />

Einen Ausweg aus der Problematik monolithischer Systeme bieten geschichtete<br />

Systeme;<br />

das Betriebssystem besteht aus einer Hierarchie abstrakter Maschinen.<br />

Jede Schicht hat wohldefinierte Schnittstellen und eine wohldefinierte<br />

Aufgabe<br />

Reduktion der Systemkomplexität.<br />

Geschichtete Systeme ermöglichen die Realisierung von Systemfamilien,<br />

d.h. ein neues Familienmitglied (und damit eine neue Plattform für<br />

Anwendungen) kann mit vergleichsweise geringem Aufwand auf irgendeiner<br />

abstrakten Maschine aufgesetzt werden. Unter der Voraussetzung, dass die<br />

122


Schlichter, TU München 4.2. BETRIEBSSYSTEM - ÜBERBLICK<br />

Schnittstellen präzis und in sich konsistent festgelegt wurden, kann jede<br />

abstrakte Maschine unabhängig von anderen erstellt werden. Dies bietet<br />

auch die Möglichkeit, einzelne Schichten durch neue Implementierungen zu<br />

ersetzen, solange Schnittstelle und Aufgabe eingehalten werden. Gerade im<br />

Bereich der Rechnernetze spielt das Schichtenkonzept eine sehr wichtige Rolle<br />

(siehe ISO/OSI Referenzmodell oder TCP/IP Referenzmodell).<br />

Mikrokern-Ansatz<br />

Anwendungen<br />

Funktionsschnittstelle<br />

abstrakte Maschine N<br />

Funktionsschnittstelle<br />

abstrakte Maschine N - 1<br />

Funktionsschnittstelle<br />

abstrakte Maschine 0<br />

Rechnerhardware<br />

Schicht N<br />

Schicht N-1<br />

Schicht 0<br />

Der Trend moderner Betriebssystem geht hin zu einem Mikrokern-Ansatz. Im<br />

Mikrokern sind nur mehr Basismechanismen, z.B. Prozesskommunikation (Austausch<br />

von Nachrichten), CPU-Zuteilung. Möglichst viele Subsysteme sind als<br />

Systemprozesse außerhalb des Mikrokerns realisiert. Sie laufen im Benutzermodus<br />

ab, z.B. Dateisystem, Verwaltungsstrategien, Speicherverwaltung. Man<br />

spricht im Zusammenhang mit diesem Ansatz auch von einer Client/Server-<br />

Struktur. Systemfunktionen werden als Serverprozesse im Benutzermodus ausgeführt.<br />

Benötigt ein Prozess (Client) eine Dienstleistung schickt er eine An-<br />

123


Schlichter, TU München 4.2. BETRIEBSSYSTEM - ÜBERBLICK<br />

forderung an einen anderen Prozess (Server), der die Dienstleistung erfüllt und die<br />

Antwort an den Client zurückgibt. Die Kommunikation zwischen den beteiligten<br />

Prozesse erfolgt über den Mikrokern. Durch die Ausgliederung in Serverprozesse<br />

ist eine Trennung von Mechanismus und Strategie möglich. Die Strategien werden<br />

in Serverprozesse im Benutzermodus realisiert, während der Mikrokern wenige<br />

Basismechanismen beinhaltet.<br />

Einfaches Austauschen von Subsysteme ermöglicht die einfache Anpassung<br />

von Systemanforderungen.<br />

Benutzer<br />

Programm<br />

Prozess<br />

Server<br />

Anforderung<br />

Antwort<br />

Memory<br />

Server<br />

Beispiel: BS-Architekturen<br />

File<br />

Server<br />

Mikrokern<br />

Hardware<br />

Netzwerk<br />

Server<br />

Display<br />

Server<br />

Benutzer-Modus<br />

(User Mode)<br />

System-Modus<br />

(Kernel Mode)<br />

¯ Unix Betriebssystem<br />

Die nachfolgende Abbildung skizziert die wesentlichen Komponenten des<br />

Unix Betriebssystems. Der Unix-BS-Kern enthält die Datei-, Prozess- und<br />

Prozessorverwaltung, die Speicherverwaltung und die Geräte-Treiber. Zur<br />

Nutzung beispielsweise der Systemdienste des Dateisystems bietet das BS u.a.<br />

die Dienste ÓÔÒ Ö ÛÖØ ÐÓ× an. Bibliotheken enthalten u.a. die<br />

Routinen für Standard-Ein/Ausgabe sowie malloc-Funktion zur dynamischen<br />

Speicherverwaltung.<br />

124


Schlichter, TU München 4.2. BETRIEBSSYSTEM - ÜBERBLICK<br />

Programme Shells<br />

Datei<br />

System<br />

Geräte Treiber<br />

Systemschnittstelle<br />

u.a. open,close, read, write; fork, exec, kill, ...<br />

Prozess<br />

verwaltung<br />

Unterbrechungs<br />

behandlung<br />

Hardware<br />

Prozessor<br />

verwaltung<br />

Bibliotheken<br />

(z.B. lib.a)<br />

Arbeitsspeicher<br />

verwaltung<br />

Benutzungsschnittstelle<br />

Programmierschnittstelle<br />

Betriebssystemkern<br />

¯ Windows NT Betriebssystem<br />

Mit Hilfe von HAL wird versucht, die meisten Maschinenabhängigkeiten zu<br />

verbergen. HAL präsentiert dem restlichen BS abstrakte Hardwaregeräte.<br />

Der Kernel ist kein Mikrokern. Zielsetzung des Kernels ist die vollständige<br />

Hardware-Unabhängigkeit, und damit sehr portable BS-Komponenten höherer<br />

Ebene. Der Kernel besteht aus Control-Objects (z.B. primitive Prozessobjekte,<br />

Unterbrechungsobjekte) und Dispatcher-Objects (z.B. Semaphore, Ereignisse,<br />

Timer). Der Kernel ist auch zuständig für das Scheduling von Threads. Der<br />

Objektmanager verwaltet alle Systemobjekte (z.B. Prozesse, Threads, Dateien,<br />

Semaphore). Der Prozessmanager ist für die Erzeugung, Verwaltung und<br />

Löschung von Prozessen und Threads verantwortlich. Die Local Procedure<br />

Call Facility realisiert eine effiziente Interprozess-Kommunikation zwischen<br />

den Subsystemen. Die System Services stellt die Schnittstelle zum Executive<br />

bereit.<br />

125


Schlichter, TU München 4.2. BETRIEBSSYSTEM - ÜBERBLICK<br />

Object<br />

Manager<br />

Logon<br />

Process<br />

Security<br />

Subsystem<br />

Security<br />

Manager<br />

Hardware Manipulation<br />

OS/2 Client<br />

OS/2<br />

Subsystem<br />

4.2.4 Betriebsarten<br />

System Interface (DLL)<br />

Process<br />

Manager<br />

Kernel<br />

System Services<br />

Local<br />

Procedure<br />

Call Facility<br />

Hardware Abstraction Layer (HAL)<br />

Hardware<br />

Win32<br />

Client<br />

Win32<br />

Subsystem<br />

Virtual<br />

Memory<br />

Manager<br />

Posix Client<br />

Posix<br />

Subsystem<br />

Systemaufrufe<br />

I/O Manager<br />

File Systems<br />

Cache Mgr<br />

User Mode<br />

Kernel Mode<br />

Device Drivers<br />

Network<br />

Drivers<br />

Applications<br />

Protected<br />

Subsysteme<br />

(Servers)<br />

NT Executive<br />

Beim Betrieb von Rechenanlagen können bzgl. des Zusammenwirkens von Benutzer<br />

und Rechensystem die Betriebsweisen Stapelverarbeitung, Dialogbetrieb<br />

und Echtzeitbetrieb unterschieden werden.<br />

¯ Stapelbetrieb<br />

Das Rechensystem verarbeitet Ströme von Auftragspaketen (engl. batch processing).<br />

Ein Benutzer deklariert vollständig alle Teile eines Auftragspaketes,<br />

bevor es in das System eingegeben wird. Anschließend wird das Auftragspaket<br />

durch das Rechensystem abgearbeitet, ohne dass der Benutzer noch Einflussmöglichkeiten<br />

hat. Bei Auftreten eines Fehlers muss i.a. nach der Korrektur<br />

das gesamte Auftragspaket nochmals gestartet werden. Auftragspakete<br />

können in Unterabschnitte zerfallen, z.B. Teilprogrammabläufe. Diese Betriebsart<br />

war in den Anfängen von Rechenanlage sehr verbreitet (Nutzung von<br />

Lochkarten und Lochstreifen).<br />

¯ Dialogbetrieb<br />

126


Schlichter, TU München 4.3. PROZESSVERWALTUNG<br />

Im Dialogbetrieb erteilt der Benutzer dem Betriebssystem einen Auftrag<br />

nach dem anderen im Dialog. Innerhalb eines Benutzerauftrags findet<br />

eine Interaktion zwischen dem Benutzer und der Systemumgebung statt<br />

(z.B. Eingabe weiterer Daten, Ausgabe von Zwischenergebnissen). Der<br />

Dialogbetrieb erfordert eine besondere Gestaltung der Benutzerschnittstelle.<br />

Oft wird Betriebssystem und Benutzerschnittstelle (engl. user interface) in<br />

einem Atemzug genannt und auch oft gleichgesetzt. Beide sind jedoch getrennt<br />

voneinander zusehen. Beispielsweise existierten mit dem X11-Windowsystem<br />

und Sun Windowsystem (auf der Basis von Postscript) zwei unterschiedliche<br />

Benutzerschnittstellen auf demselben Betriebssystem.<br />

¯ Echtzeitbetrieb<br />

In der Prozessteuerung (automatische Fertigungssysteme, Roboter) und im<br />

Multimediabereich sind die Reaktionszeiten des Betriebssystems von großer<br />

Bedeutung. Dies erfordert spezielle Mechanismen bei der Behandlung von<br />

Ereignissen und Unterbrechungen sowie der CPU-Zuteilung an rechenbereite<br />

Prozesse / Threads. Beispielsweise ein Videoserver (bei Nutzung des Streaming<br />

Ansatzes) benötigt ein Betriebssystem, das gewisse Echtzeitfähigkeiten hat.<br />

Videos müssen mit einer bestimmten Geschwindigkeit abgespielt werden. Die<br />

Bilder dürfen an das Abspielprogramm nicht zu langsam (ansonsten ruckelt<br />

das Videobild) und nicht zu schnell ausgeliefert werden (sonst gehen bei<br />

Pufferüberlauf Videobilder verloren).<br />

4.3 Prozessverwaltung<br />

Dieser Abschnitt behandelt das Prozesskonzept, Datenstrukturen zur Beschreibung<br />

des aktuellen Prozesszustandes sowie Dienste zum Aufruf von Systemfunktionen.<br />

4.3.1 Prozesskonzept<br />

Wir unterscheiden Benutzerprozesse, die Anwendungsprogrammen in Ausführung<br />

entsprechen, und Systemprozesse, die Programme/Dienste des Betriebssystems<br />

durchführen.<br />

127


Schlichter, TU München 4.3. PROZESSVERWALTUNG<br />

a) Jeder Prozess besitzt einen eigenen Prozessadressraum.<br />

b) Spezielle Systemprozesse sind die Dämonen (engl. daemon); das sind<br />

Hilfsprozesse, die ständig existieren, die meiste Zeit aber passiv sind. Sie<br />

erfüllen i. d. R. Service-Funktionen und werden dazu durch das Eintreten<br />

von Ereignissen aufgeweckt (z.B. Datei zum Drucken eingetroffen) oder<br />

werden von Zeit zu Zeit aktiv, um selber zu prüfen, ob Dienste zu<br />

erbringen sind.<br />

Dienste der Prozessverwaltung<br />

Die Prozesse werden durch das Betriebssystem verwaltet.<br />

Prozess-Erzeugen und Starten (z.B. fork).<br />

Terminieren, Auflösen (z.B. exit, kill).<br />

Prozess-Auswahl, Strategien zur Prozessorzuteilung: Scheduling (z.B.<br />

change-priority). Der Scheduler ist für Multitasking-Betriebssysteme<br />

von Bedeutung. Er wählt den nächsten auszuführenden Prozess aus<br />

der Menge der rechenbereiten Prozesse aus. Dabei werden in den<br />

Betriebssystemen unterschiedliche Verfahren angewandt, z.B. Auswahl nach<br />

Prioritäten oder Zeitscheibenverfahren (Round Robin). Eine ausführlichere<br />

Diskussion verschiedener Strategien erfolgt später und im Hauptstudium<br />

(Betriebssysteme).<br />

Prozessor-Anbindung; Dispatching (z.B. suspend, resume, sleep, wakeup).<br />

Die Durchführung des Übergangs eines Prozesses in den Zustand rechnend<br />

erfolgt durch den Dispatcher. Beispielsweise teilt er den vom Scheduler<br />

ausgewählten Prozess der CPU zu. Der Prozess geht vom Zustand<br />

rechenbereit in den Zustand rechnend über; der Prozess wird ausgeführt.<br />

Dabei muss sichergestellt, dass der entsprechende Kontext des Prozesses (z.B.<br />

seine Register) geladen werden.<br />

Prozesskontrollblock<br />

Jeder Prozess muss als eine Verwaltungseinheit beschrieben sein. Ein Prozess<br />

wird durch seinen Prozess-Kontext und dieser durch den Prozesskontrollblock<br />

(PCB) beschrieben. Ein PCB wird meist programmiersprachlich als Verbund<br />

(record) spezifiziert. Ein PCB (process control block) enthält i.d.R. folgende<br />

Informationen:<br />

¯ eindeutiger Name, z.B. fortlaufende Nummerierung des Prozesses (z.B. pid in<br />

Unix)<br />

128


Schlichter, TU München 4.3. PROZESSVERWALTUNG<br />

¯ Name des Benutzers, dem der Prozess zugeordnet ist<br />

¯ der momentane Prozesszustand (wartend, rechnend, rechenwillig, ...)<br />

¯ falls der Prozess rechnend ist, Angabe des zugeordneten Rechnerkerns<br />

¯ falls der Prozess wartend ist, eine Spezifikation des Ereignisses, auf das der<br />

Prozess wartet (z.B. Adresse eines Semaphors).<br />

¯ die Ablaufpriorität des Prozesses<br />

¯ die Inhalte der programmierbaren Register (z.B. in MI: R0, .. , R15)<br />

¯ die Inhalte der Register, in denen die Anfangsadresse und Länge<br />

der prozessspezifischen Speicherabbildungstabellen enthalten sind (virtuelle<br />

Adressierung) (z.B. in MI P0B für die Seitentabelle)<br />

¯ das Programmstatuswort (PSW). Das PSW enthält weitere Informationen,<br />

die der Rechnerkern über den Prozess kennt. In der MI enthält PSW den<br />

Zustand der CC-Register, z.B. das N-Register (Ergebnis der letzten Operation<br />

negativ), den Ablaufmodus (Benutzer- oder Systemmodus), die momentane<br />

Ablaufpriorität, die Adressierungsart im Benutzermodus (virtuelle oder direkte<br />

Adressierung). Daneben kann ein PCB noch weitere Statistiken über die<br />

Historie des Prozesses speichern, die beim Scheduling ausgewertet werden.<br />

Prozesslisten<br />

Die Prozesse werden in Zustandslisten verwaltet, die als verkettete Liste der PCBs<br />

realisiert sind.<br />

für E/A-Geräte (z.B. Platte, Terminal) existiert i.d.R. eine jeweils eigene<br />

Warteschlange, die die PCBs der wartenden Prozesse enthält.<br />

Rechnend<br />

Rechenwillig<br />

Ready-Queue<br />

Wartend<br />

129<br />

Prozessidentifikation<br />

Registerzustand<br />

Scheduling Information (z.B.<br />

Priorität)<br />

Adressrauminformation<br />

Sonstiges<br />

nächster PCB<br />

Prozesskontrollblock PCB


Schlichter, TU München 4.3. PROZESSVERWALTUNG<br />

Bei der MI steht während der Zuordnung eines Rechnerkerns an einen Prozess<br />

die Maschinenadresse des zugehörigen PCB in dem Sonderregister PCBADR des<br />

Rechnerkerns. Da der PCB eine Datenstruktur des Betriebssystems ist, kann die<br />

Ablage nicht im Benutzeradressraum erfolgen. Da weiterhin die Prozesse nicht<br />

kellerartig aktiviert und deaktiviert werden, sondern in beliebiger Folge, kann er<br />

auch nicht im Keller des Betriebssystems abgelegt werden, sondern es wird dafür<br />

die Halde verwendet.<br />

Zustandsmodell<br />

Das Prozess-Zustandsmodell unterscheidet neben den bereits vorgestellten<br />

Zuständen rechenwillig, rechnend, wartend auch den Zustand ausgelagert.<br />

Letzterer Zustand tritt ein, wenn der Adressraum aufgrund Speichermangels aus<br />

dem Arbeitsspeicher auf den Hintergrundspeicher verlagert wird ("swapping").<br />

add retire<br />

rechenwillig<br />

assign rechnend<br />

swap in<br />

ready<br />

resign<br />

wartend<br />

ausgelagert<br />

130<br />

block<br />

swap out


Schlichter, TU München 4.3. PROZESSVERWALTUNG<br />

Zustandsübergänge<br />

: ein neu erzeugter Prozess wird zu der Menge bereiten Prozesse<br />

hinzugefügt;<br />

××Ò: als Folge eines Kontextwechsels wird dem Prozess die CPU<br />

zugeordnet;<br />

ÐÓ : aufgrund eines EA-Aufrufs oder einer Synchronisationsoperation<br />

wird der Prozess wartend gesetzt;<br />

ÖÝ: nach Beendigung der angestoßenen Operation wechselt der Prozess<br />

in den Zustand rechenwillig; er bewirbt sich erneut um die CPU;<br />

Ö×Ò: dem rechnenden Prozess wird die CPU entzogen; er bewirbt sich<br />

anschließend erneut um die CPU;<br />

ÖØÖ: der aktuell rechnende Prozess terminiert;<br />

×ÛÔ ÓÙØ: der Prozess wird auf den Hintergrundspeicher ausgelagert;<br />

×ÛÔ Ò: der Prozess wird vom Hintergrundspeicher in den Arbeitsspeicher<br />

geladen.<br />

4.3.2 Dispatcher<br />

Aufgabe des Dispatchers: Realisieren der Zustandsübergänge zwischen rechnend<br />

und rechenwillig: Prozessor binden und entbinden. Dazu ist ein Kontextwechsel<br />

erforderlich. Dabei ist zu berücksichtigen, dass die Prozesslisten entsprechend<br />

aktualisiert werden, d.h. der PCB des ausgewählten Prozess muss aus der<br />

rechenwillig-Liste entfernt werden und in die rechnend-Liste eingetragen werden.<br />

Kontextwechsel<br />

CPU wird entzogen und einer anderen Aktivität zugeteilt; ein Kontextwechsel ist<br />

erforderlich, falls der rechnende Prozess P1 in den Zustand wartend oder z.B.<br />

durch Prozessorentzug in den Zustand rechenwillig übergeführt wird.<br />

¯ Problem<br />

aktueller Ausführungskontext des Prozesses muss gesichert werden und<br />

Kontext des nächsten rechenbereiten Prozesses muss geladen werden. Falls<br />

für den Zugriff auf eine Datei X nur ein Dateizeiger zur Verfügung steht, dann<br />

muss die Position des Dateizeigers gerettet werden. Wenn Prozess P1 wieder<br />

rechnend wird, dann soll er an der Position weiterlesen, an der er unterbrochen<br />

wurde; falls zwischenzeitlich ein anderer Prozess P2 ebenfalls die Datei gelesen<br />

und den Dateizeiger verändert hat, darf dies bei der Fortsetzung von P1 keine<br />

Auswirkung haben. In Unix erhält jeder Prozess einen eigenen Dateizeiger.<br />

Achtung: je umfangreicher ein PCB ist, desto "teurer" sind Prozesswechsel,<br />

d.h. das Umschalten der CPU zwischen den Prozessen.<br />

131


Schlichter, TU München 4.3. PROZESSVERWALTUNG<br />

Threads<br />

Threads haben einen sehr viel kleineren Kontext Umschalten zwischen<br />

Threads innerhalb eines Prozesses sehr schnell, da Adressraum und andere<br />

Ressourcen (z.B. Dateien) gemeinsam genutzt werden. Auch TLB-Einträge<br />

( Translation lookaside Buffer (siehe Seite 175)) der Seitenadressierung<br />

müssen nicht invalidiert werden. Damit ergeben sich auch keine Folgekosten<br />

durch Laden von Seiten bei cache-Misses. Dagegen ist das Umschalten von<br />

Threads, die unterschiedlichen Prozessen angehören, ebenso aufwendig wie ein<br />

Prozesswechsel.<br />

Beispiel: Kontext-Wechsel in Unix<br />

Kontextwechsel z.B. durch den Aufruf der Systemoperation sleep durch einen<br />

Prozess. Beim Aufruf der Operation sleep ist ein Warteraum, in den der<br />

Prozess eingefügt werden soll, anzugeben (z.B. E/A-Warteraum, oder warten<br />

auf Terminieren eines Kind-Prozesses). Bei der Ausführung von sleep werden<br />

vergröbert folgende Schritte durchgeführt.<br />

1. Maskieren von Interrupts;<br />

2. Lokalisieren der benötigten Warteschlange;<br />

3. Neuberechnung der Priorität des Prozesses;<br />

4. Einfügen des Prozesses in die Warteschlange;<br />

5. Aufruf der Operation zum Kontextwechsel.<br />

Bei der Ausführung der Operation zum Kontextwechsel wird vom Scheduler<br />

der nächste Prozess ausgesucht, dem der Prozessor zugeteilt werden soll,<br />

und mit dieser Information wird die Operation resume aufgerufen. Zunächst<br />

wird der Zustand des noch aktuellen Prozesses aus den Registern in den<br />

Prozesskontrollblock des Prozesses gespeichert. Dann wird die Adresse des<br />

Prozesskontrollblocks des neu zu bindenden Prozesses sowie der Zustand des<br />

neuen Prozesskontrollblocks in die Register geladen und der Kontextwechsel<br />

ist durchgeführt. Durch das Maskieren von Interrupts kann das Warten auf die<br />

relevanten Ereignisse eingestellt werden, d.h. die anderen Interrupts werden<br />

ausgeblendet.<br />

4.3.3 Arbeitsmodi<br />

Ziel für den Betrieb von Rechensystemen: kontrollierter Zugriff auf Hardwarekomponenten<br />

nur durch BS. Dadurch soll verhindert werden, dass Benutzer<br />

oder Softwaresysteme Hardwarekomponenten unsachgemäß nutzen, und implizit<br />

andere nebenläufige Aktivitäten schädigen.<br />

132


Schlichter, TU München 4.3. PROZESSVERWALTUNG<br />

Lösung: alle Zugriffe auf Hardware nur über privilegierte Befehle zulässig;<br />

Frage: wer darf privilegierte Befehle ausführen Antwort: Prozesse in<br />

einem privilegierten Modus.<br />

Herkömmlich unterscheidet man zwischen dem Benutzer- (engl. user mode) und<br />

dem Systemmodus (engl. kernel mode).<br />

¯ Benutzermodus<br />

Es sind nur die nicht privilegierten Befehle verfügbar. Damit ist der Zugriff auf<br />

Prozessadressraum und unkritische Register, wie Befehlszähler, Indexregister<br />

möglich. Benutzerprozesse werden im Benutzermodus ausgeführt.Kritische<br />

Register, über die der Kontext eines Prozesses beeinflusst werden kann<br />

(z.B. Ablaufpriorität, Arbeitsmodus) können nur im Systemmodus verändert<br />

werden. Wird versucht, einen privilegierten Befehl auszuführen, gibt es einen<br />

Befehlsalarm.<br />

¯ Systemmodus<br />

Es sind auch die privilegierten Befehle verfügbar (z.B. Anhalten der Maschine,<br />

Verändern der Ablaufpriorität). Die Dienste des Betriebssystemkerns werden<br />

im Systemmodus ausgeführt.<br />

¯ Nutzung der Hardware-Komponenten nur über Dienste des BS: Aufruf eines<br />

BS-Dienstes über spezielle Befehle: den Systemaufruf. Dies führt zu einer <br />

Unterbrechung (siehe Seite 150) und damit zu einem kontrollierten Eingang in<br />

das BS (z.B. Zugriffsrechte des aufrufenden Prozesses prüfen).<br />

4.3.4 Systemaufrufe<br />

Ein Systemaufruf ist eine Funktion, die von einem Benutzerprozess aufgerufen<br />

wird, um einen BS-Kerndienst aufzuführen.<br />

1. Der Systemaufruf überprüft die übergebenen Parameter und bildet daraus<br />

eine Datenstruktur, um die Daten an den BS-Kern weiterzureichen.<br />

2. Danach wird eine spezielle Instruktion, ein Software Interrupt (Trap),<br />

ausgeführt. Diese Instruktion identifiziert über einen Operanden den<br />

gewünschten Systemdienst.<br />

3. Bei Ausführung der Trap-Instruktion wird der Zustand des Benutzerprozesses<br />

gerettet und es findet ein Wechsel in den Systemmodus statt.<br />

In manchen Programmiersprachen sind Systemaufrufe (C, C++) über den<br />

Aufruf von Prozeduren der Laufzeitumgebung, die ihrerseits die Systemaufrufe<br />

durchführen, möglich. In Java ist kein direkter Systemaufruf möglich, sondern<br />

dies erfolgt i.a. über Methoden, die in anderen Sprachen geschrieben sind, meist<br />

C, C++.<br />

133


Schlichter, TU München 4.3. PROZESSVERWALTUNG<br />

Beispiel<br />

Lesen von Daten aus einer Datei und Kopieren in eine andere Datei. Dabei treten<br />

die folgenden Systemaufrufe auf:<br />

(1) Schreiben des Prompts auf Bildschirm: Angabe der Dateinamen<br />

(2) Lesen der Tastatureingabe (bzw. Analoges bei Mouse-Eingabe)<br />

(3) Öffnen der zu lesenden Datei (open)<br />

(4) Erzeugen der neuen Datei<br />

(5) ggf. Fehlerbehandlung: Nachricht auf Bildschirm<br />

(6) Schleife: Lesen von Eingabedatei (ein Systemaufruf) und schreiben in zweite<br />

Datei (auch Systemaufruf)<br />

(7) Schließen beider Dateien<br />

(8) Ausgabe auf Bildschirm<br />

Durch die Verwendung von Laufzeitroutinen ergibt sich eine höhere Abstraktionsebene<br />

Aufruf einer Routine, die die notwendigen Systemaufrufe durchführt.<br />

Privilegierte MI Befehle<br />

Die Modellmaschine MI unterstützt die folgenden privilegierten Maschinenbefehle:<br />

134


Schlichter, TU München 4.3. PROZESSVERWALTUNG<br />

a) das Anhalten der Maschine: HALT<br />

b) Laden des PCB in den Rechnerkern: LPCB; die Adresse des PCB steht im<br />

Register PCBADR. Die Adresse des PCB im Speicher ergibt sich durch<br />

die Adresse im Register PCBADR. PC und PSW aus dem PCB werden<br />

nicht in die aktuellen Register übernommen, sondern in den Keller für<br />

den Systemmodus abgelegt (bei der Fortsetzung können dann die Register<br />

entsprechend besetzt werden).<br />

c) Speichern des PCB (vom Rechnerkern) : SPPCB; Die Zieladresse im<br />

Speicher ergibt sich durch die Adresse im Register PCBADR. PC und<br />

PSW werden nicht aus den aktuellen Registern, sondern vom Keller<br />

genommen und im PCB im Speicher abgelegt.<br />

d) Rückkehr aus Unterbrechungen: REI (return from interrupt); Prozess,<br />

dessen PCB geladen ist, wird fortgesetzt.<br />

e) Speichern von Sonderregistern: SPSR a1; Das Sonderregister wird<br />

immer rechtsbündig in ein Wort abgespeichert. Links wird mit Null<br />

aufgefüllt, da die Sonderregister nicht immer Wortlänge haben. Siehe<br />

dazu auch die MI-Beschreibung.<br />

f) Laden von Sonderregistern: LSR a1; Es wird der zu ladende Wert für das<br />

Sonderregister immer rechtsbündig in einem Wort erwartet.<br />

g) Auslösen eines Rechnerkernalarms : RKALARM a1, wobei S[a1] die<br />

Nummer des zu unterbrechenden Rechnerkerns angibt. Die MI kann bis<br />

zu 4 Rechnerkerne haben, die von 0 bis 3 nummeriert sind.<br />

Folgende Größen bzw. Hardware Komponenten sind nur mit privilegierten<br />

Befehlen veränderbar:<br />

¯ der Arbeitsmodus.<br />

¯ der Adressierungsmodus. Hier wird zwischen virtuelle Adressierung<br />

(Seitenadressierung) und direkter Adressierung unterschieden. Letztere<br />

Adressierungsart ermöglicht auch den Zugriff auf den physischen Speicher.<br />

¯ die Register mit Adresse oder Länge der Speicheradressierungstabellen.<br />

¯ das Register PCBADR mit der Adresse des Prozesskontrollblocks PCB.<br />

¯ das Register SCBADR mit der Adresse des Systemkontrollblocks SCB.<br />

Der Systemkontrollblock beinhaltet die Startadressen für die Routinen zur<br />

Behandlung von Unterbrechungen, z.B. wenn Befehlsalarm auftritt oder eine<br />

Rückmeldung eines Kanals eintrifft.<br />

135


Schlichter, TU München 4.3. PROZESSVERWALTUNG<br />

Systemaufrufe in der MI<br />

Systemdienste werden über Zahlen identifiziert. Ein Systemaufruf in der MI<br />

erfolgt mit dem Befehl CHMK. Nach dem oben Gesagten führt der Befehl<br />

CHMK daher bei der MI zu einer Unterbrechung. Es findet ein Übergang von<br />

einem Programmstück im Benutzermodus (Benutzer- oder Systemprozess) zu<br />

einem Programmstück im Systemmodus statt. Der Systemkern läuft in einem<br />

anderen Programmadressraum und mit einem anderen Arbeitsmodus. Daher muss<br />

muss der momentane Ablaufzustand (Rechnerkernzustand) gesichert werden und<br />

ein neuer Ablaufzustand eingestellt werden. Es muss auch mindestens der<br />

aktuelle PC und das PSW gerettet werden. Der neue Ablaufzustand, z.B. die<br />

Einsprungadresse in den Systemkern, darf aus Sicherheitsgründen nicht durch den<br />

Aufrufer, der ja nicht vertrauenswürdig ist, definiert werden. Es erfolgt daher eine<br />

Standardbesetzung. Diese Standardbesetzung ist wie bei den später besprochenen<br />

Unterbrechungen. Der Befehl CHMK führt in der MI zu einer Unterbrechung.<br />

CHMK a1 Aufruf eines Systemdienstes a1 ("CHange Mode to<br />

Kernel")<br />

¯ Wirkung des Befehls CHMK<br />

Auch das Betriebssystem verfügt analog zum Benutzerprozess über einen<br />

Systemkeller.<br />

– Ablage von PSW und PC des aufrufenden Prozesses auf dem Systemkeller.<br />

– Der Operand a1 gibt die Nummer des aufgerufenen Systemdienstes<br />

an. Diese Nummer wird ebenfalls auf dem Systemkeller abgelegt<br />

und kann vom Systemkern ausgewertet werden. Weitere Parameter<br />

für den Systemdienst werden in einem Versorgungsblock bereitgestellt.<br />

Der Ort dieses Versorgungsblockes muss vereinbart werden. Achtung<br />

bei Adressübergaben:<br />

Adressräumen!<br />

Aufrufer und Systemkern evtl. in getrennten<br />

– Zustand des Systemkellers nach der Ausführung von CHMK:<br />

Bit 0 - 31<br />

SP+8 PSW<br />

SP+4 PC<br />

SP S[a1]<br />

– Der Eintrag "vorhergehender Arbeitsmodus" im PSW wird mit dem<br />

gegenwärtigen Arbeitsmodus besetzt. Der gegenwärtige Arbeitsmodus ist<br />

der beim Aufruf von CHMK gültige Arbeitsmodus. Er wird gerettet.<br />

– Der aktuelle Arbeitsmodus wird der Systemmodus.<br />

136


Schlichter, TU München 4.3. PROZESSVERWALTUNG<br />

– Der Befehlszähler PC wird auf die Adresse für die Behandlung von Systemdiensten<br />

gemäß dem Systemkontrollblock eingestellt (Systemdienstanfangsbehandlung).<br />

¯ Rückkehr von Systemaufruf in MI<br />

REI Rückkehr von der Unterbrechungsbehandlung (REturn from Interrupt)<br />

Es werden die Register PC und PSW gemäß den Werten auf dem<br />

Systemkeller besetzt. Dies entspricht der Einstellung des alten Zustandes<br />

des aufrufenden Prozesses, insbesondere bezüglich PC, Arbeitsmodus und<br />

Adressierungsmodus. Der Prozess, der den Systemdienst aufgerufen hat, wird<br />

also fortgesetzt.<br />

– Zustand des Systemkellers vor der Ausführung von REI:<br />

Bit 0 - 31<br />

SP+4 PSW<br />

SP PC<br />

4.3.5 Realisierung von Threads<br />

Es existieren zwei grundlegende Ansätze, Threads in einem Rechensystem<br />

zu realisieren: im Benutzer-Adressraum (Benutzermodus) oder im System-<br />

Adressraum (Systemmodus).<br />

¯ im Benutzer-Adressraum<br />

Der BS-Kern verwaltet nur single-threaded Prozesse. Damit ist es auch möglich<br />

ein Thread-Package für ein Betriebssystem zu realisieren, das auf BS-Ebene<br />

keine Threads unterstützt.<br />

Prozess Thread<br />

Laufzeitsystem<br />

Thread<br />

tabelle<br />

BS-Kern<br />

137<br />

Prozesstabelle<br />

Benutzer<br />

Adressraum<br />

(Benutzermodus)<br />

System<br />

Adressraum<br />

(Systemmodus)


Schlichter, TU München 4.3. PROZESSVERWALTUNG<br />

– Threads werden durch Laufzeitsystem im Benutzeradressraum verwaltet.<br />

Eine Thread-Tabelle speichert Informationen (Register, Zustand, etc.) über<br />

Threads pro Prozess.<br />

– Prozessorzuteilung im BS-Kern erfolgt an Prozesse. Laufzeitsystem<br />

bestimmt, welcher Thread rechnend gesetzt wird. Jedes Laufzeitsystem<br />

hat seinen eigenen Thread-Scheduler. Damit ist es möglich, dass jeder<br />

Prozess seine eigene Variante des Scheduling-Algorithmus nutzt, d.h. die<br />

Auswahl des nächsten auszuführenden Threads. Beispielsweise kann durch<br />

eine geeignete Strategie verhindert werden, dass der Garbage Collector zu<br />

einem ungünstigen Zeitpunkt unterbrochen wird.<br />

– Problem: Systemaufruf eines Threads blockiert die anderen Threads<br />

des Prozesses. Dadurch wird gerade dies verhindert, was mit Threads<br />

in Applikationen erreicht werden soll, d.h. die Ausführung paralleler<br />

Aktivitätssequenzen, wobei trotz Blockierung einiger Threads andere<br />

Threads desselben Prozesses weiterlaufen können.<br />

– Problem: wie wird einem Thread die CPU entzogen? Threads müssen die<br />

CPU durch Ausführung des Befehls ØÖÝÐ freiwillig aufgeben. Das<br />

Laufzeitsystem wählt dann einen anderen rechenwilligen Thread aus. Falls<br />

ein Thread die CPU nicht aufgibt, kann ihm vom Laufzeitsystem (nicht wie<br />

im BS-Kern) die CPU entzogen werden. Innerhalb eines Prozesses existieren<br />

keine Clock-Interrupts.<br />

¯ im System-Adressraum<br />

Neben den Prozessen werden im BS-Kern auch alle Threads verwaltet.<br />

Damit können auch alle Funktionen zur Verwaltung von Prozessen, z.B.<br />

CPU-Zuteilung, für Threads verwendet werden. Dies bedeutet jedoch auch,<br />

dass bei Erzeugung bzw. Terminierung von Threads jeweils Systemaufrufe<br />

durchgeführt werden müssen. Systemaufrufe sind jedoch i.a. aufwendig.<br />

138


Schlichter, TU München 4.3. PROZESSVERWALTUNG<br />

Prozess Thread<br />

BS-Kern<br />

Thread<br />

tabelle<br />

Prozesstabelle<br />

Benutzer<br />

Adressraum<br />

(Benutzermodus)<br />

System<br />

Adressraum<br />

(Systemmodus)<br />

– Thread-Tabelle speichert Informationen (Register, Zustand, etc.) über<br />

Threads.<br />

– Prozessorzuteilung im BS-Kern erfolgt an Threads. Falls ein Thread<br />

blockiert, kann die Prozessorzuteilung entscheiden, ob ein anderer Thread<br />

aus demselben Prozess die CPU zugeteilt bekommt, oder ein Thread eines<br />

anderen Prozesses.<br />

– Der Systemaufruf eines Threads blockiert nicht die anderen Threads des<br />

Prozesses.<br />

¯ Es wurden auch hybride Ansätze verfolgt, die eine Kombination beider<br />

Möglichkeiten realisieren. Der BS-Kern verwaltet sogenannte Kernel-Threads.<br />

Das Betriebssystem kennt nur Kernel-Threads und teilt diese der CPU zur<br />

Ausführung zu. Threads des Benutzer-Adressraums (User-Threads) werden<br />

jeweils auf Kernel-Threads abgebildet, dabei können gleichzeitig mehrere<br />

User-Threads eines Prozesses verfügbaren Kernel-Threads zugeordnet werden.<br />

Auf einen einzelnen Kernel-Thread können gleichzeitig auch mehrere User-<br />

Threads abgebildet werden (Multiplexing).<br />

139


Schlichter, TU München 4.4. PROZESSORVERWALTUNG<br />

Benutzer<br />

Adressraum<br />

(Benutzermodus)<br />

System<br />

Adressraum<br />

(Systemmodus)<br />

Prozess<br />

BS-Kern<br />

4.4 Prozessorverwaltung<br />

Kernel<br />

Thread<br />

User-Thread<br />

Eine wesentliche Aufgabe der Prozessorverwaltung besteht darin zu entscheiden,<br />

welcher der um den bzw. die Prozessor(en) konkurrierenden Prozesse (bzw.<br />

Threads) zu einem Zeitpunkt an den bzw. die Prozessor(en) gebunden wird.<br />

Dazu steht die BS-Komponente Scheduler zur Verfügung. Die Durchführung<br />

der Zustandsübergangs (siehe Seite 130) eines Prozesses von rechenwillig<br />

nach rechnend ist Aufgabe des Dispatchers, während der Scheduler aus der Liste<br />

der möglichen Prozesse einen geeigneten auswählt. Der Scheduler wählt den<br />

Prozess aus, der durch einen assign-Zustandsübergang nach rechnend übergeht.<br />

In folgenden Situationen muss ein Scheduler auf jeden Fall aktiviert werden:<br />

ein neuer Prozess wird erzeugt;<br />

ein Prozess terminiert;<br />

ein Prozess blockiert aufgrund eines EA-Auftrags;<br />

eine EA-Unterbrechung tritt auf.<br />

Daneben kann das Betriebssystem einem Prozess die CPU entziehen, falls er<br />

bereits zulange rechnend ist (Ablauf der Zeitscheibe).<br />

4.4.1 Kriterien<br />

Der Scheduler wählt aus der Menge der rechenwilligen Prozesse den nächsten<br />

auszuführenden Prozess aus. Es existieren unterschiedliche Verfahren die von der<br />

jeweiligen Prozessorverwaltungsstrategie abhängen. Mögliche Leistungskriterien<br />

für ein Schedulingverfahren:<br />

140


Schlichter, TU München 4.4. PROZESSORVERWALTUNG<br />

¯ Fairness. Jeder Prozess soll einen fairen Anteil der CPU zum Rechnen erhalten.<br />

¯ Effizienz, Prozessorauslastung. Dies ist ein Maß für die Auslastung eines<br />

Prozessors. Ziel sollte es sein, dass möglichst alle Teile der Rechenanlage<br />

effizient genutzt werden, z.B. CPU und EA-Geräte sollten möglichst gut<br />

ausgelastet sein.<br />

¯ Antwortzeit für interaktive Benutzer (Dialogverarbeitung). Für interaktive Anwendungen<br />

muss die Zeitspanne zwischen Ankunft, z.B. einer Benutzereingabe<br />

und einer potentiellen Reaktion möglichst kurz sein.<br />

¯ Wartezeit, insbesondere für Batch-Jobs (Stapelverarbeitung). Darunter ist die<br />

Verweilzeit in der Bereit-Liste zu verstehen, d.h. die Zeitdauer in der einem<br />

rechenwilligen Prozess kein physischer Prozessor zugeordnet ist.<br />

¯ Abschlusszeit, insbesondere für Realzeitsysteme. Hier geht es darum, ob die<br />

Realzeitgarantien eingehalten werden. Wird der Prozess rechtzeitig fertig und<br />

liefert seine Ergebnisse aus (z.B. das Videobild)?<br />

¯ Durchsatz, Anzahl der Aufträge pro Zeiteinheit. Mit den Leistungskriterien gibt<br />

es Probleme: a) die Optimierungsziele sind teilweise widersprüchlich (z.B. eine<br />

Strategie, die den Durchsatz optimiert ist nicht notwendigerweise geeignet, um<br />

kurze Antwortzeiten zu ermöglichen), und b) das Prozessverhalten (z.B. wann<br />

kommt der nächste E/A-Befehl) kann vom Scheduler nicht exakt vorausgesagt<br />

werden. Deshalb werden Scheduling-Strategien meist abhängig von der<br />

Betriebsart gewählt (Dialogbetrieb vs. Stapelbetrieb).<br />

4.4.2 Scheduling-Strategien<br />

Es werden zwischen zwei Klassen unterschieden: nicht-unterbrechende (nonpreemptive)<br />

und unterbrechende Strategien (preemptive).<br />

nicht unterbrechend: Scheduling nur dann möglich, wenn der rechnende<br />

Prozess blockiert wird oder wenn er terminiert, d.h. Prozess behält CPU bis<br />

er sie selber abgibt.<br />

Beispiel: Microsoft Windows 3.x; unterbrechende Strategien erst ab<br />

Windows 95<br />

unterbrechend: Unterbrechung beim Eintreten von speziellen Ereignissen,<br />

u.a. Eintreffen eines Prozesses mit höherer Priorität oder Prozess geht in<br />

Wartezustand. Problematisch ist diese Strategie für die Ausführung von<br />

Operationen des BS-Kerns. Lösung bei vielen Betriebssystemen (z.B. Unix):<br />

Ausführung von BS-Kernoperationen sind nicht unterbrechbar (Vorsicht: hier<br />

in bezug auf Scheduling, Interrupts können auftreten).<br />

141


Schlichter, TU München 4.4. PROZESSORVERWALTUNG<br />

Zeitscheibenstrategie<br />

Die Zeitscheibenstrategie (Round Robin) ist unterbrechend. Ziel ist die<br />

gleichmäßige Verteilung der Rechenzeit auf rechenwillige Prozesse. Round Robin<br />

ist eine weit verbreitete preemptive Schedulingvariante. Das Verfahren ordnet<br />

jedem rechenwilligen Prozess ein definiertes Zeitquantum (Zeitscheibe) zu. In 4.3<br />

BSD Unix beträgt z.B. die Zeitscheibe 100 ms. Nach dem Kontextwechsel ist der<br />

Prozess entweder bis zum Ablauf des Zeitquantums oder bis zum Auftreten einer<br />

blockierenden Systemfunktion im Besitz der CPU. Alle rechenwilligen Prozesse<br />

werden in einer FIFO-Warteschlange verwaltet. Nach Ablauf der Zeitscheibe wird<br />

der Prozess am Ende der FIFO-Warteschlange eingereiht.<br />

¯ Es werden die Prozesse an den Prozessor jeweils für ein festgelegtes<br />

Zeitquantum q gebunden und spätestens nach dem Ablauf dieser Zeitspanne<br />

wird den Prozessen der Prozessor wieder entzogen.<br />

¯ zyklisches Bedienen der Prozesse (Round Robin).<br />

¯ Ready-Queue (Liste der rechenwilligen Prozesse) als zyklische Warteschlange<br />

realisiert.<br />

¯ Wahl des Zeitquantums:<br />

falls q zu klein: viele unproduktive Kontextwechsel. Es scheint, als ob jeder<br />

Prozess seinen eigenen Prozessor besitzt; process sharing.<br />

falls q zu groß: Round Robin wird zu einem reinen FCFS Scheduling<br />

(First Come First Served), da die Wahrscheinlichkeit für einen Aufruf<br />

eines blockierenden Systemdienst steigt. Ein zu großes Zeitquantum ist<br />

insbesondere für interaktive Anwendungen nicht empfehlenswert, da sich<br />

die Wartezeit für einen Prozess, und damit die Reaktionszeit erhöht.<br />

Typische Werte für q: 10 bis 100 Millisekunden.<br />

¯ Für q = 100 ms gilt bei 1 MIPS Maschine: ca. 100.000 Instruktionen/q.<br />

Prioritäten<br />

Diese Strategie ist i.a. unterbrechend. Sie basiert darauf, an die Prozesse<br />

Prioritäten zu vergeben. Die Prioritätenvergabe kann dabei statisch oder<br />

dynamisch sein. Die Prioritätenstrategie kann unterbrechend und nichtunterbrechend<br />

sein. Im ersten Fall wird der Ablauf eines Prozesses unterbrochen,<br />

wenn ein anderer Prozess mit höherer Priorität rechenwillig wird. Im zweiten<br />

Fall behält der Prozess die CPU solange bis er entweder eine blockierende<br />

Systemfunktion aufruft oder die CPU freiwillig abgibt.<br />

142


Schlichter, TU München 4.4. PROZESSORVERWALTUNG<br />

¯ Prioritäten sind i.a. ein festgelegter Zahlenbereich, z.B. 0, ..., 7. Achtung:<br />

häufig: niedrige Zahl entspricht hoher Priorität, muss aber nicht so sein.<br />

¯ Statische Prioritätenvergabe<br />

jeder Prozess besitzt für die Dauer seiner Existenz eine feste Priorität.<br />

Problem: Gefahr des Verhungerns von Prozessen mit niedriger Priorität<br />

Lösung: Erhöhung der Priorität von lange wartenden Prozessen, d.h.<br />

dynamische Prioritäten.<br />

¯ Dynamische Prioritätenvergabe<br />

die Prioritäten der Prozesse können sich dynamisch verändern, d.h. sie werden<br />

in gewissen Zeitabständen neu berechnet.<br />

Idee: lange Wartezeiten berücksichtigen (Erhöhen die Priorität).<br />

Prozesse mit großem CPU-Verbrauch sinken in Priorität.<br />

E/A-intensive Prozesse steigen in Priorität (damit E/A-Geräte und CPU<br />

parallel genutzt werden).<br />

¯ Zeitscheibenstrategien und Prioritätenvergabe können zu effizienten Verwaltungsstrategien<br />

kombiniert werden. Beispielsweise können Prozesse in Prioritätsklassen<br />

gruppiert werden. Innerhalb einer Gruppe wird die Zeitscheibenstrategie<br />

verwendet. Beispielweise können 4 Prioritätsklassen eingerichtet werden,<br />

wobei die Klasse 4 die höchste Priorität hat. Solange Prozesse in der<br />

Klasse 4 sind, werden diese jeweils im Zeitscheibenverfahren ausgewählt. Falls<br />

die Klasse 4 leer, werden Prozesse der Klasse 3 ausgewählt usw. Prozesse<br />

müssen dynamisch den Klassen zugeordnet werden, damit nicht Prozesse der<br />

untersten Klasse verhungern.<br />

First-Come First-Served<br />

Dieses nicht-unterbrechende Verfahren (FCFS) teilt einen Prozessor in der<br />

Reihenfolge des Auftragseingangs zu. Ready-Queue wird als FIFO-Liste<br />

verwaltet; Verfahren einfach zu realisieren.<br />

¯ Ein Kontextwechsel findet nur statt, wenn der Prozess eine blockierende<br />

Systemfunktion aufruft oder der Prozess die CPU freiwillig abgibt. Im letzten<br />

Fall wird der Prozess sofort wieder am Ende der Ready-Queue eingereiht. Im<br />

ersten Fall wird der Prozess nach Ende der Blockierungsursache wieder am<br />

Ende der Ready-Queue eingereiht.<br />

¯ Es kann eine hohe CPU Auslastung erreicht werden.<br />

143


Schlichter, TU München 4.4. PROZESSORVERWALTUNG<br />

¯ Problem: Durchschnittliche Wartezeit ist hoch.<br />

Beispiel: Prozesse P1,P2,P3 kommen nahezu gleichzeitig zum Zeitpunkt 0<br />

an;<br />

Dauer ihrer Berechnungszeiten: P1: 24 ms, P2: 3ms, P3: 3ms;<br />

bei Reihenfolge P1, P2, P3: mittlere Wartezeit: (0 + 24 + 27)/3 = 17 ms<br />

bei Reihenfolge P2, P3, P1 mittlere Wartezeit (0+3+6)/3 = 3 ms<br />

Shortest-Jobs-First<br />

Dieses Verfahren (SJF) führt die Prozessorzuteilung in der Reihenfolge der<br />

wachsenden Rechenphasen ("CPU-Burst") zu, d.h. Prozess mit kürzester,<br />

nächster Rechenphase erhält Prozessor als nächster. Das Verfahren ist nur bedingt<br />

realisierbar, da die Länge des nächsten CPU-Bursts a priori nicht bekannt ist.<br />

In der Praxis wird daher eine Approximation eingesetzt, die auf der Basis der<br />

gemessenen Länge der zurückliegenden Bursts und einem Schätzwert für den<br />

nächsten Burst ermittelt wird.<br />

¯ anwendbar, falls die Dauer der nächsten Rechenphase bis E/A-Befehl, Interrupt<br />

etc. bekannt ist.<br />

¯ Beispiel: P1: 6ms, P2: 8ms, P3: 7ms, P4: 3ms<br />

Schedule bei SFJ : P4, P1, P3, P2; Wartezeit: (3+16 +9 +0) /4 = 7 ms<br />

bei FCFS: 10.25 ms (P1 vor P2 vor P3 vor P4)<br />

¯ Problem: Kenntnis über die Bedienzeiten erforderlich. Für Stapelbetrieb<br />

geeignet, da dort Information über Rechenzeiten zur Verfügung stehen<br />

(Benutzer geben bei Batch-Jobs Rechenzeit an). Für SJF gibt es wieder<br />

nicht-unterbrechende und unterbrechende Varianten. Im letzteren Fall wird<br />

ein Prozess unterbrochen, falls ein Prozess rechenwillig, dessen nächste<br />

Rechenphase kürzer ist als die noch verbleibende Rechenzeit des momentan<br />

rechnenden Prozesses.<br />

Animation Scheduling<br />

siehe online Version<br />

4.4.3 Beispiel Unix Scheduling<br />

Beim Unix-Scheduling handelt sich um eine Zeitscheibenstrategie mit dynamischer<br />

Prioritätenvergabe. Unix vergibt für seine Prozesse Prioritäten von 0 - 127<br />

(0 ist die höchste Priorität), die in 32 Warteschlangen verwaltet werden. Alle<br />

144


Schlichter, TU München 4.4. PROZESSORVERWALTUNG<br />

Prozesse einer Prioritätsklasse befinden sich in einer Warteschlange, die nach einer<br />

Round-Robin Strategie abgearbeitet wird. Zunächst wird allen Prozessen der<br />

höchsten Priorität die CPU zugeteilt bis die Warteschlange leer ist. Dann kommen<br />

die Prozesse mit der nächstniedrigeren Priorität zum Zuge. Die Prioritäten werden<br />

fortlaufend neu berechnet (multilevel-feedback-queue). Die Prioritäten der<br />

Prozesse, die in einem gewissen Zeitabschnitt viel Rechenzeit verbraucht haben,<br />

werden erniedrigt; Prozesse, die lange gewartet haben, erhalten eine höhere Priorität.<br />

¯ Zeitscheibenstrategie pro Warteschlange bis Warteschlange leer; dann Scheduling<br />

mit nächst niedrigerer Warteschlange.<br />

¯ dynamische Berechnung der Prozesspriorität:<br />

ÙÔÖÓ ÍËÊÈÊÁÇ Ô ÔÙ ÔÒ <br />

p_cpu ist die Prozessornutzung des rechnenden Prozesses und wird alle 10 ms<br />

um 1 inkrementiert.<br />

p_nice ist ein vom Benutzer bestimmter Gewichtungsfaktor (-20 p_nice <br />

20).<br />

USER_PRIO ist die Priorität, die dem Prozess beim Start zugeteilt worden ist.<br />

Der Wert von p_cpu wird jede Sekunde angepasst<br />

Ô ÔÙ ÐÓ ÐÓ Ô ÔÙ ÔÒ <br />

load ist eine Abschätzung der CPU-Auslastung.<br />

Die Anpassung (2) sorgt dafür, dass die bisher verbrauchte Rechenzeit nach<br />

einer gewissen Zeit nicht mehr ins Gewicht fällt. Das "short-term-scheduling"<br />

unterstützt das interaktive Arbeiten am Rechner. Die Prioritäten von Prozessen,<br />

die lange auf die Ausführung von E/A-Operationen warten, werden erhöht.<br />

Dagegen werden die Prioritäten von Prozessen, die wesentliche CPU-Zeiten auf<br />

sich vereinigen, verringert. Dies bedeutet zusammenfassend, dass ”interaktive”<br />

Prozesse den ”Batch”-Prozessen vorgezogen werden.<br />

4.4.4 Thread Scheduling<br />

Die Prozessorzuteilung von Threads hängt von deren Art der Realisierung<br />

(siehe Seite 137) ab.<br />

User-Threads<br />

Realisierung der Threads im Benutzeradressraum Kern hat keine Kenntnis<br />

bzgl. der Threads. BS-Scheduler wählt nur Prozess aus. Laufzeitsystem des<br />

145


Schlichter, TU München 4.4. PROZESSORVERWALTUNG<br />

Prozesses wählt rechenwilligen Thread des Prozesses aus; es kann ein beliebiges<br />

Scheduling-Verfahren (siehe Seite 141) für Prozesse verwendet werden. Da<br />

auf der Ebene des Laufzeitsystems keine Zeitunterbrechungen (clock interrupts)<br />

bearbeitet werden (sie werden auf Betriebssystem-Ebene bearbeitet), können<br />

Threads so lange laufen, bis sie selbst die CPU freiwillig aufgeben, d.h. ein<br />

Thread kann vom Laufzeitsystem aufgrund des Ablaufs einer Zeitscheibe nicht<br />

unterbrochen werden.<br />

¯ Java Virtual Machines verwenden unterbrechendes Prioritäten-Scheduling für<br />

Threads;<br />

10 ist die höchste und 1 die niedrigste Priorität;<br />

Ein rechenwilliger höher priorer Thread führt zur Unterbrechung eines<br />

rechnenden niedriger prioren Thread ("unterbrechender Scheduler").<br />

Weiterhin kann ein Thread auch freiwillig die CPU aufgeben ("cooperative<br />

scheduler"). Probleme treten auf, wenn Threads die gleiche Priorität haben.<br />

Falls ein cooperative Scheduler verwendet wird, ist der aktuelle Thread<br />

solange rechnend, bis er freiwillig die CPU aufgibt. Falls er dies nicht<br />

macht, sind die anderen rechenwilligen Threads nur wartend (Gefahr des<br />

Verhungerns).<br />

Ein unterbrechender Thread-Scheduler wird in gewissen Zeitabständen<br />

den aktuell rechnenden Thread unterbrechen, und andere Threads gleicher<br />

Priorität auswählen.<br />

Das Ablauf-Verhalten hängt vom Scheduling Verfahren der jeweiligen JVM<br />

Implementierung ab, z.B. Windows verwendet unterbrechendes Thread<br />

Scheduling, während der Mac cooperative Thread Scheduling realisiert<br />

(möglicherweise anders bei MacOS 10).<br />

Kernel-Threads<br />

Realisierung der Threads im Systemadressraum<br />

nächsten auszuführenden Thread aus.<br />

BS-Scheduler wählt den<br />

a) Ist ausgewählter Thread demselben Prozess zugeordnet wie der vorher<br />

rechnende Thread geringer Kontextwechsel.<br />

b) Ist ausgewählter Thread nicht demselben Prozess zugeordnet wie der<br />

vorher rechnende Thread aufwendiger Kontextwechsel. In diesem<br />

Fall findet auch ein Adressraumwechsel statt, d.h.<br />

Speicherabbildung müssen angepasst werden.<br />

die Register zur<br />

146


Schlichter, TU München 4.4. PROZESSORVERWALTUNG<br />

4.4.5 Mehrschichtiges Scheduling<br />

Der Scheduler wählt einen der rechenwilligen Prozesse aus. Da diese aber u.U.<br />

nicht alle im Arbeitsspeicher vorliegen (Speicherknappheit) und ein Einlagern<br />

eines Prozesses von der Platte in den Arbeitsspeicher aufwendig ist, verfügen<br />

Systeme häufig über ein Mehr-Schichten Scheduling.<br />

¯ Short-Term-Scheduler (CPU Scheduler)<br />

Auswahl eines geeigneten Prozesses aus der Ready-Queue; wird häufig<br />

aufgerufen; Verfahren siehe oben.<br />

¯ Long-Term-Scheduler<br />

Auswahl rechenwilliger neuer Aufträge (meist Jobs aus dem Hintergrundbetrieb<br />

(batch)) und Einlagerung in den Arbeitsspeicher; Einfügen der Prozesse<br />

in die Ready-Queue. Scheduler kontrolliert den Multiprogramming-Grad, d.h.<br />

wieviele Prozesse im Arbeitsspeicher liegen. Long-Term-Scheduler wird relativ<br />

selten aufgerufen. Wenn ein Prozess das System verläßt, wird dieser Scheduler<br />

u.U. erst nach mehreren Minuten aufgerufen.<br />

Kriterium: guten Prozessmix erzielen, d.h. Mischung aus E/Aintensiven<br />

und rechenintensiven Prozessen (nur E/A-intensiv: Ready-<br />

Queue häufig leer, CPU nicht ausgelastet, andersherum: E/A-Geräte<br />

schlecht ausgelastet).<br />

Long-term Scheduling ist nicht immer vorhanden: z.B. in Unix nicht, jeder<br />

neue Prozess wird in Arbeitsspeicher geladen. Eine andere Zwischenstufe ist<br />

Medium-term-Scheduling: bei Überlast werden Prozesse auf Hintergrundspeicher<br />

ausgelagert (swap out) und später wieder eingelagert (swap in).<br />

¯ Graphische Darstellung<br />

147


Schlichter, TU München 4.4. PROZESSORVERWALTUNG<br />

swap-in<br />

Long-term<br />

Scheduler<br />

Ready Queue<br />

CPU Scheduler<br />

E/A-Warteschlange<br />

Zeit-Interrupt-<br />

Warteschlange<br />

Ausführung im<br />

BS-Kern<br />

4.4.6 Echtzeit Scheduling<br />

ausgeswappte<br />

Prozesse<br />

neue<br />

Aufträge<br />

swap-out<br />

CPU fertig<br />

E/A-Befehl<br />

Zeitscheibe<br />

abgelaufen<br />

sleep-Befehl<br />

Systemaufruf<br />

In Multimedia-Umgebungen treten die zu verarbeitenden kontinuierlichen Daten<br />

(Empfangen, Dekodierenen und Anzeigen von Videoframes) in bestimmten,<br />

meist periodischen Zeitabständen auf. Die Operationen auf diese Daten<br />

wiederholen sich dabei immer wieder und sollen bis zu einem gewissen<br />

Zeitpunkt abgeschlossen sein. Prozesse in Multimedia-Anwendungen führen<br />

oft zeitkritische Operationen aus. Bzgl. des Scheduling existieren zwei<br />

gegensätzliche Ziele:<br />

148


Schlichter, TU München 4.4. PROZESSORVERWALTUNG<br />

a) ein unkritischer Prozess sollte nicht dauerhaft blockiert werden, weil<br />

zeitkritische Prozesse eine Ressource gänzlich auslasten. Daher sollten<br />

zeitkritische Prozesse und Verwaltungsarbeiten nicht die gesamte Kapazität<br />

einer Ressource beanspruchen.<br />

b) zeitkritische Prozesse dürfen nicht durch Scheduling-Verfahren (Round-<br />

Robin oder Prioritäten) am zeitkritischen Fortschritt gehindert werden<br />

Einhaltung von Zeitvorgaben.<br />

¯ Zuordnung von Kenngrößen zu zeitkritischen Prozessen<br />

Bereitzeit (ready time): frühestmöglicher Ausführungsbeginn einer<br />

Aktivität.<br />

Frist (deadline): spätester Zeitpunkt für die Beendigung einer Aktivität.<br />

Ausführungszeit: worst-case Abschätzung für das zur vollständigen<br />

Ausführung einer Aktivität notwendige Zeitintervall.<br />

In vielen Fällen werden Aktivitäten periodisch ausgeführt. Deshalb werden<br />

hierzu neben der Ausführungszeit Kenngrößen wie Frequenz der Aktivität<br />

(Periode) und Versatz des Ausführungsbeginns relativ zum Anfang der Periode<br />

(Phase) erfasst.<br />

¯ Earliest Deadline First (EDF)<br />

Der Prozessor wird immer dem Prozess mit der am nächsten in der Zukunft<br />

liegenden Frist zugeordnet. Es existieren die beiden Varianten: nichtunterbrechend<br />

und unterbrechend. Fasst man die Fristen als Prioritäten<br />

auf, dann entspricht dieses Verfahren im Prinzip dem prioritäten-basierten<br />

Scheduling.<br />

– nicht-unterbrechend<br />

Eine Prozessorzuordnung bleibt bis der Prozess eine blockierende Systemfunktion<br />

aufruft oder freiwillig die CPU abgibt. Neue eintreffende Prozesse<br />

mit kürzeren Fristen werden erst beim nächsten Scheduling berücksichtigt.<br />

– unterbrechend<br />

Diese Variante führt einen Kontextwechsel durch, wenn ein Prozess mit<br />

einer kürzeren Frist rechenwillig wird. Man kann zeigen, dass die<br />

preemptive Variante immer eine Abarbeitungsreihenfolge mit Einhaltung<br />

aller Zeitvorgaben findet, solange mindestens eine solche Reihenfolge<br />

existiert.<br />

¯ Rate-Monotonic Scheduling<br />

Rate-Monotonic Scheduling (RMS) ist für periodische Prozesse; RMS ordnet<br />

Prioritäten in Abhängigkeit von der Periode zu.<br />

149


Schlichter, TU München 4.5. UNTERBRECHUNGSKONZEPT<br />

1) Prozesse mit der höchsten Frequenz (kleinste Periode) erhalten die<br />

höchste Priorität.<br />

2) Prozesse mit der geringsten Frequenz (längste Periode) erhalten die<br />

niedrigste Priorität.<br />

Die Priorität ist statisch; sie ändert sich nicht für den Rest der Prozesslaufzeit.<br />

Prioritäten geben die relative Wichtigkeit eines Prozesses gegenüber der<br />

Wichtigkeit anderer Prozesse im Rechensystem wider. RMS ist relativ einfach<br />

zu handhaben und sie erlaubt eine Abschätzung, ob eine Echtzeitanwendung<br />

auf einer bestimmten Rechenanlage ohne Fristverletzung ausgeführt werden<br />

kann oder nicht.<br />

– Auswahl der Prozesse anhand ihrer Priorität. Jedoch auch unter Berücksichtigung<br />

der anderen Kenngrößen, wie z.B. Bereitzeit.<br />

– hochfrequente Prozesse werden minimal verzögert.<br />

– Zerstückelung niederfrequenter Prozesse, da sie häufig wegen hochfrequenter<br />

Prozesse unterbrochen werden.<br />

4.5 Unterbrechungskonzept<br />

Die optimale Ausnutzung und Auslastung aller Geräte eines Rechensystems legt<br />

Mehrprogrammbetrieb nahe. Zerlegung der Ausführungsphasen eines Programms<br />

in viele Einzelteile;<br />

- Aufbrechen der Ausführung eines Prozesses in mehrere Phasen: u.a.<br />

Rechnen, E/A, Synchronisieren mit Partner.<br />

- Die Ausführung der Programme wird in der Regel mehrfach unterbrochen.<br />

4.5.1 Motivation<br />

Ursachen für Unterbrechungen<br />

zugeteilte Prozessorzeit ist aufgebraucht;<br />

benötigte Ressourcen stehen aktuell nicht zur Verfügung;<br />

ein E/A-Gerät meldet sich zurück;<br />

ein Fehler tritt auf, z.B. Division durch 0;<br />

Systemaufruf (wurde bereits als spezielle Unterbrechung eingeführt);<br />

¯ Bei einer Unterbrechung wird ein gerade aktiver Prozess unterbrochen<br />

und eine Unterbrechungsbehandlung durchgeführt. Nach Beendigung der<br />

Unterbrechungsbehandlung kann prinzipiell ein beliebiger rechenbereiter<br />

Prozess fortgesetzt werden.<br />

150


Schlichter, TU München 4.5. UNTERBRECHUNGSKONZEPT<br />

¯ Es ist erforderlich, bei der Unterbrechung den Rechnerkernstatus des gerade<br />

aktiven Prozesses für die spätere Fortsetzung zu speichern. Als Minimum ist<br />

dabei der Befehlszähler und das Programmstatuswort zu retten, da diese bei<br />

der Einstellung des neuen Zustandes bei der Unterbrechungsausführung im<br />

Rechnerkern verändert werden. Weitere Zustandsinformation wird dann in der<br />

Unterbrechungsbehandlung des Betriebssystems gerettet.<br />

¯ Forderung: Eine Unterbrechung muss so kontrolliert erfolgen, dass ein<br />

definierter Prozessstatus festgehalten werden kann.<br />

4.5.2 Unterbrechungsarten<br />

Die normale Programmausführung eines Prozessors kann auch durch mehrere<br />

Arten von Unterbrechungen verändert werden. Man unterscheidet zwischen<br />

synchronen und asynchronen Unterbrechungen.<br />

Trap<br />

Unterbrechung<br />

synchron asynchron<br />

Alarme<br />

(Exception)<br />

Externe, asynchrone Unterbrechungen<br />

Interrupt<br />

Dies sind Unterbrechungen (Interrupts), die von außerhalb des zu unterbrechenden<br />

Prozesses ausgelöst werden, z.B. E/A-Kanal-"Endmeldung". Asynchrone<br />

Unterbrechungen sind Ereignisse im Rechensystem, die über besondere Steuerbusleitungen<br />

an den Prozessor weitergegeben werden. Asynchron bedeutet in<br />

diesem Kontext, dass der eintreffende Interrupt in keiner kausalen Beziehung zum<br />

aktuell ausgeführten Befehl steht.<br />

¯ Der Ablauf im Rechnerkern (RK) wird unterbrochen und eine Unterbrechungsanfangsbehandlung<br />

des Betriebsystemkerns wird aktiviert.<br />

151


Schlichter, TU München 4.5. UNTERBRECHUNGSKONZEPT<br />

E/A-Kanal 2 CPU (RK) BS-Kern<br />

Ende E/A<br />

Auftrag<br />

Interne, synchrone Unterbrechungen<br />

Unterbrechungsbehandlung<br />

(UBH)<br />

Dies sind Unterbrechungen (Alarme, Exceptions), die durch den zu unterbrechenden<br />

Prozess selbst ausgelöst werden, z.B. Division durch 0. Synchrone Unterbrechungen<br />

sind eine unmittelbare Folge der aktuellen Befehlsausführung. Sie<br />

können auch explizit durch einen speziellen Befehl (Trap) ausgelöst werden. Mit<br />

Hilfe von Traps werden Systemdienste im Betriebssystem aufgerufen. Im Fehlerfall<br />

spricht man auch von Alarmen ("exceptions").<br />

¯ Der Ablauf im RK wird unterbrochen und eine Unterbrechungsanfangsbehandlung<br />

des Systemkerns wird aktiv.<br />

152


Schlichter, TU München 4.5. UNTERBRECHUNGSKONZEPT<br />

CPU (RK) BS-Kern<br />

Unterbrechung<br />

arithmetischer Alarm<br />

Unterbrechungsbehandlung<br />

(UBH)<br />

4.5.3 Behandlung externer Unterbrechungen<br />

Synchrone und asynchrone Unterbrechungen haben hardwaremäßig die Speicherung<br />

des aktuellen Prozessorzustandes zur Folge und lösen im Anschluss<br />

daran einen indirekten Sprung über eine im Speicher befindliche Sprungtabelle<br />

aus. Dabei ordnet der Prozessor jeder synchronen und asynchronen Unterbrechung<br />

einen festen Index in der Sprungtabelle zu. An dieser Stelle steht die<br />

Anfangsadresse der Unterbrechungsroutine, die entsprechende Folgemaßnahmen<br />

einleitet. Falls möglich (Ausnahme ist z.B. ein arithmetischer Alarm) kann die unterbrochene<br />

Programmausführung durch die Wiederherstellung des gespeicherten<br />

Prozessorzustandes zu einem beliebigen, späteren Zeitpunkt fortgesetzt werden.<br />

Ablauf<br />

¯ Geräte-Controller meldet Unterbrechung über spezielle Interrupt-Leitung an<br />

CPU.<br />

¯ CPU prüft im Befehlszyklus nach jeder Befehlsausführung, ob eine Unterbrechung<br />

gemeldet wurde.<br />

¯ Falls Unterbrechung vorliegt: sichern u.a. des aktuellen Befehlszählers, des<br />

Programmstatusworts und Sprung zu einer Unterbrechunganfangsbehandlung,<br />

die an festgelegter Speicheradresse steht. Die restlichen Informationen, wie<br />

Register, werden dann von der Unterbrechungsbehandlung gesichert.<br />

153


Schlichter, TU München 4.5. UNTERBRECHUNGSKONZEPT<br />

Routine untersucht Unterbrechungsursache, die vom Controller über<br />

Datenleitung gemeldet wird (Unterbrechungsnummer).<br />

über Unterbrechungsnummer erfolgt die Auswahl der benötigten Unterbrechungsbehandlungsroutine;<br />

Nummer ist i.a. Index in eine Tabelle, dem<br />

Unterbrechungsvektor.<br />

Vektor enthält Speicheradresse der Unterbrechungsbehandlungsroutine.<br />

4.5.4 Konflikte<br />

Konflikte bei Unterbrechungen treten z.B. in folgenden Situationen auf:<br />

(1) während einer Unterbrechungsbehandlung treten weitere Unterbrechungen<br />

auf;<br />

(2) es treffen gleichzeitig mehrere Unterbrechungswünsche ein.<br />

¯ Beispiel<br />

E/A-Kanal 1 und E/A-Kanal 2 erledigen beide Aufträge für Prozess A.<br />

E/A-Kanal 1 Prozess A BS-Kern E/A-Kanal 2<br />

externe<br />

Unterbrechung<br />

Ende E/A<br />

Auftrag<br />

¯ Mögliche Konfliktlösungen<br />

Unterbrechungsbehandlung<br />

(UBH)<br />

Konflikt<br />

externe<br />

Unterbrechung<br />

Ende E/A<br />

Auftrag<br />

– Andere Unterbrechungen nicht zulassen, d.h. Maskierung von Unterbrechungen;<br />

anstehende Unterbrechung ignorieren oder vorläufig zurückstellen;<br />

Problem: u.a. Rechtzeitigkeit der Unterbrechungsbehandlung.<br />

154


Schlichter, TU München 4.5. UNTERBRECHUNGSKONZEPT<br />

– Interne Unterbrechungen erfolgen stets sofort und geben der zugehörigen<br />

Unterbrechungsbehandlung dieselbe Priorität, wie sie der unterbrochene<br />

Ablauf hatte. Die Benutzerprozesse haben die niedrigste Ablaufpriorität,<br />

nämlich 0. Unterbrechungen von Unterbrechungsbehandlungen sind<br />

möglich.<br />

– Externe Unterbrechungen erhalten Prioritäten z.B. (0,...,31) zugeordnet. Die<br />

aufgerufene Unterbrechungsbehandlung erhält die Priorität (Ablaufpriorität)<br />

der auslösenden Unterbrechung.<br />

Eine weitere externe Unterbrechung wird während einer Unterbrechungsbehandlung<br />

zugelassen, wenn die Priorität der neuen Unterbrechung<br />

höher als die Ablaufpriorität der gerade aktiven Unterbrechungsbehandlung<br />

ist. Trifft dieser Fall nicht zu, so wird der Unterbrechungswunsch<br />

zurückgestellt, bis ein Ablauf mit einer niedrigeren<br />

Ablaufpriorität aktiv wird.<br />

Konsequenz: Unterbrechungsroutinen müssen ablaufinvariant sein!<br />

¯ Integration der Unterbrechungsbehandlung in den Befehlszyklus der CPU<br />

prüfen ob interne Unterbrechung aufgetreten,<br />

falls ja, Behandlung der Unterbrechung<br />

sonst : prüfen ob externe Unterbrechung mit höherer Priorität. Wenn ja<br />

wähle eine mit höchster Priorität.<br />

Bei Unterbrechung: sichere alten Zustand, stelle neuen Zustand her und<br />

führe ersten Befehl der Unterbrechungsbehandlungsroutine aus.<br />

¯ Beispiel: Festlegungen in der MI<br />

Die Anzahl und die Anfangsadressen der Unterbrechungsbehandlungen sind<br />

vom jeweiligen Betriebssystem abhängig. Ein Systemkontrollblock (SCB)<br />

enthält Startadressen der Unterbrechungsbehandlungsroutinen. Die Adresse<br />

des SCB wird in einem Register des RK, dem Sonderregister SCBADR,<br />

gehalten.<br />

155


Schlichter, TU München 4.5. UNTERBRECHUNGSKONZEPT<br />

U-Nr. Relativadresse U-Priorität Art der Unterbrechung<br />

1 +0 31 katastrophaler<br />

Fehler<br />

2 +4 übernommen Befehlsalarm<br />

3 +8 übernommen Speicherschutzalarm<br />

4 +12 übernommen Seite-fehlt-alarm<br />

5 +16 übernommen Trace<br />

6 +20 übernommen arithmetischer<br />

Alarm<br />

7 +24 übernommen CHMK<br />

temaufruf)(Sys-<br />

8 +28 übernommen - (reserviert)<br />

9 +32 25 Rechnerkernalarm<br />

10 +36 24 Weckeralarm<br />

11 +40 23 von<br />

icherPlattenspe-<br />

12 +44 22 von Kanal 0<br />

Empfänger<br />

13 +48 22 von Kanal 0<br />

Sender<br />

14 +52 21 von Kanal 1<br />

Empfänger<br />

15 +56 21 von Kanal 1<br />

Sender<br />

16 +60 20 von Kanal 2<br />

Empfänger<br />

17 +64 20 von Kanal 2<br />

Sender<br />

18 +68 19 von Kanal 3<br />

Empfänger<br />

19 +72 19 von Kanal 3<br />

Sender<br />

Anmerkung 1: Die Unterbrechungsnummern und die Unterbrechungsprioritäten<br />

stehen nicht im Systemkontrollblock, sondern sie sind den Unterbrechungen<br />

implizit zugeordnet. Anmerkung 2: Das "Tracing" ist eine Testhilfe auf<br />

sehr niederer Ebene. Ist "Tracing" eingestellt, dann wird nach jedem Maschinenbefehl<br />

der Rechnerkern unterbrochen und eine Unterbrechungsbehandlung<br />

aufgerufen. In dieser UBH kann dann der Status des Rechnerkerns, insbeson-<br />

156


Schlichter, TU München 4.5. UNTERBRECHUNGSKONZEPT<br />

dere die Werte in den Registern, abgefragt oder ausgedruckt werden. Das<br />

"Tracing" ist sehr zeitaufwendig und sollte daher auf die nicht getesteten Befehlsfolgen<br />

im Benutzerprogramm beschränkt werden. Daher wird das "Tracing"<br />

automatisch ausgeschaltet, während Systemdienste oder allgemeiner Unterbrechungen<br />

im Systemkern ausgeführt werden, da diese Teile getestet sind<br />

und da der Benutzer diese Befehlfolgen ohnehin nicht kennt.<br />

157


Kapitel 5<br />

Speicherverwaltung<br />

Der Adressraum ist eine zentrale Abstraktion, die von der Systemsoftware eines<br />

Rechensystems zur Verfügung gestellt werden muss. Über den Adressraum sind<br />

alle für die Ausführung eines Anwendungsprogramms notwendigen Operationen<br />

und Datenstrukturen zugreifbar. Allgemein wird ein Adressraum durch eine<br />

zusammenhängende Menge von Adressen und deren Inhalte definiert. Die<br />

maximale Größe eines Adressraums kann aus dem Adressbusaufbau der<br />

verwendeten Prozessorarchitektur abgeleitet werden. Modernde Rechensysteme<br />

unterscheiden zwischen den Adressräumen der Programme und dem physischen<br />

Adressraum (Arbeitsspeicher).<br />

5.1 Fragestellungen<br />

Dieser Abschnitt beschäftigt sich mit den Adressräumen für Programme und<br />

deren Abbildung auf den physischen Arbeitsspeicher einer Rechenanlage:<br />

¯ Programmadressraum vs. Maschinenadressraum.<br />

¯ Direkte Adressierung, Basisadressierung.<br />

¯ Virtualisierung des Speichers; virtuelle Adressierung, insbesondere Seitenadressierung.<br />

5.2 Einführung<br />

Die unmittelbare Nutzung des physischen Adressraums (Arbeitsspeichers) bei der<br />

Anwendungsentwicklung ist nicht empfehlenswert. Probleme sind folgende:<br />

158


Schlichter, TU München 5.2. EINFÜHRUNG<br />

- Kenntnisse über Struktur und Zusammensetzung des Arbeitsspeichers<br />

notwendig.<br />

- Kapazitätsengpässe bei der Arbeitsspeichergröße. Werden die in einem<br />

Rechensystem bei der Befehlsausführung durch den Rechnerkern auftretenden<br />

Adressen direkt als reale Speicheradressen interpretiert, so kommt man<br />

schnell in Kapazitätsengpässe. Die Kapazität des Arbeitsspeichers reicht oft<br />

nicht aus, um alle Daten darin abzulegen. Deshalb weicht man auf den Hintergrundspeicher<br />

(Platte) aus, um Teile der Daten eines Prozesses dort abzulegen.<br />

deshalb Programmerstellung unabhängig von realer Speichergröße und -<br />

eigenschaften. Abstrahieren von realen Eigenschaften der Hardware. Die<br />

Handhabung der unterschiedlichen Speicher sollte für die <strong>Programmierung</strong><br />

in höheren Programmiersprachen ohne Belang sein, d.h. der Programmierer<br />

soll sich nicht explizit um das Nachladen von benötigten Daten vom<br />

Hintergrundspeicher in den Arbeitsspeicher und umgekehrt kümmern<br />

müssen. Dies soll automatisch, d.h. transparent für den Programmierer<br />

geschehen.<br />

5.2.1 Adressräume<br />

¯ Maschinenadressraum<br />

Der Arbeitsspeicher besteht aus einer Folge von fortlaufend nummerierten<br />

Bytes. Die Nummerierung beginnt bei 0. Die Nummer des Bytes bezeichnet<br />

man als seine Adresse, genauer als seine physische Speicheradresse oder seine<br />

Maschinenadresse.<br />

Die Menge der möglichen Maschinenadressen ist der Maschinenadressraum<br />

(physischer Adressraum). Man beachte, dass bei der speicherbasierten E/A-<br />

Architekturvariante (siehe MI) die Register der E/A-Controller auch über<br />

Maschinenadressen angesprochen werden, d.h. nicht jeder Maschinenadresse<br />

ist eine Speicherzelle im Arbeitsspeicher zugeordnet.<br />

¯ Programmadressraum<br />

Wenn ein Benutzer programmiert, dann benutzt er in seinem Programm<br />

Adressen, um seine Variablen zu bezeichnen. Diese Adressen nennen wir<br />

Programmadressen.<br />

Die Menge der zulässigen Programmadressen ist der Programmadressraum.<br />

Dieser ist prozessspezifisch, d.h. Programmadressen haben nur Programmlokale<br />

Bedeutung z.B. als Sprungziele.<br />

¯ Speicherabbildung<br />

159


Schlichter, TU München 5.2. EINFÜHRUNG<br />

Der Rechnerkern muss vor jedem Zugriff auf Befehle und Operanden<br />

die jeweiligen Programmadressen in Maschinenadressen umsetzen. Diese<br />

Umsetzung wird durch Speicherabbildungen geleistet. Die wichtigsten dieser<br />

Abbildungen werden in den folgenden Abschnitten kurz vorgestellt.<br />

direkte Adressierung,<br />

Basisadressierung,<br />

Seitenadressierung und<br />

Segment-Seitenadressierung.<br />

5.2.2 Organisation von Adressräumen<br />

Im Adressraum einer Anwendung müssen alle für die Programmausführung<br />

notwendigen Daten zur Verfügung gestellt werden. Darunter fallen der Programmcode<br />

(Text), der Datenbereich (statische und dynamische Daten) und der<br />

Laufzeitkeller. Für jede dieser Informationsarten wird ein Bereich im Adressraum<br />

spezifiziert, deren Platzierung und Größe durch die Adressraumverwaltung<br />

festgelegt wird.<br />

¯ Single-Threaded Adressraum<br />

niedrige<br />

Adresse<br />

Programm<br />

statische<br />

Daten<br />

dynamische Daten<br />

(Halde)<br />

Keller<br />

hohe<br />

Adresse<br />

Die Bereiche Programmcode und statische Daten verändern sich typischerweise<br />

während der Programmausführung nicht. Dagegen können der dynamische<br />

Datenbereich (Halde) und der Laufzeitkeller an Umfang erheblich zunehmen.<br />

Beim Laufzeitkeller hängen Größenschwankungen und Ausdehnung von der<br />

maximalen Tiefe der Prozedur/Methodenschachtelung und dem Bedarf an<br />

lokalen Variablen ab.<br />

¯ Multi-Threaded Adressraum<br />

160


Schlichter, TU München 5.2. EINFÜHRUNG<br />

niedrige<br />

Adresse<br />

Programm<br />

statische<br />

Daten<br />

dynamische Daten<br />

(Halde)<br />

Keller 1<br />

Keller n<br />

hohe<br />

Adresse<br />

Für jeden Kontrollfluss (Thread) wird ein eigener Kellerbereich vorgesehen.<br />

Der Abstand zwischen den einzelnen Kellern wird meist standardmäßig vom<br />

System vorgegeben. Unabhängig von der Anzahl der Laufzeitkeller muss<br />

eine Überschneidung zwischen mehreren Kellern oder zwischen dem untersten<br />

Keller und der Halde vermieden werden.<br />

¯ Beispiel - Adressräume<br />

Moderne Betriebssysteme stellen wenigstens 32 Bit große virtuelle Adressräume<br />

für die Anwendungen zur Verfügung, die jeweils in mehrere Bereiche<br />

unterteilt sind. Programmcode, statische Daten, Halde und Laufzeitkeller der<br />

Anwendung werden jeweils in dem Bereich des Adressraums abgelegt, der der<br />

Anwendung zugänglich ist.<br />

4.4 BSD Unix<br />

Windows 95<br />

Windows NT<br />

0 1 GByte<br />

2 GByte<br />

3 GByte<br />

4 GByte<br />

spezieller Adressbereich (Größe nicht proportional)<br />

161


Schlichter, TU München 5.2. EINFÜHRUNG<br />

Der für die Anwendung nutzbare Adressbereich (weißer Bereich) schwankt<br />

zwischen ca. 2 GByte und 4 GByte. Bei allen BS wird ein unterschiedlich<br />

großer Adressbereich am Anfang (Adressen 0 und aufwärts) für jeglichen<br />

Zugriff gesperrt: bei Windows 95 sind es 4 KByte, bei Windows NT 64<br />

KByte, bei BSD Unix ist es abhängig vom Rechnertyp (4 - 8 KByte). Durch<br />

diese Sperrung wird jeder Zugriff auf diesen Bereich und damit insbesondere<br />

das Dereferenzieren eines Nullzeigers vom System abgefangen und die<br />

Programmausführung mit einer Fehlermeldung abgebrochen. In Windows 95<br />

wird zusätzlich der Adressbereich von 4 KByte - 4 MByte von der Nutzung<br />

durch 32 Bit Anwendungen ausgeklammert (Adressbereich für MS-DOS<br />

bzw 16 Bit Anwendungen). Im oberen Bereich des virtuellen Adressraums<br />

wird meist der Betriebssystemcode eingeblendet (z.B. bei Windows 95 im<br />

Bereich 1 GByte - 2 GByte; dadurch können BS-Funktionen auch ohne<br />

Adressraumwechsel genutzt werden. Bei BSD Unix und Windows NT/2000 ist<br />

dieser Bereich vor jeglichem Zugriff durch die Anwendung geschützt (oft wird<br />

sogar lesender Zugriff unterbunden). Bei Windows 95 besteht dieser Schutz<br />

nicht, d.h. Anwendungen können das Betriebssystem zum Absturz bringen.<br />

5.2.3 Fragmentierung<br />

Unter dem Begriff Fragmentierung versteht man verschiedene Formen der<br />

Zerstückelung des noch freien und nutzbaren Teils des Adressraums in kleine<br />

Bereiche. Fragmentierung kann jedesmal dann entstehen, wenn eine neue<br />

Speicherplatzanforderung aus der Menge noch freier Speicherbereiche mit einem<br />

einzigen zusammenhängenden Bereich befriedigt werden muss. Unterscheidung<br />

zwischen externer und interner Fragmentierung.<br />

¯ Externe Fragmentierung<br />

Es wechseln sich benutzte und unbenutzte Speicherbereiche innerhalb des<br />

Adressraums ab. Speicheranforderungen werden jeweils genau erfüllt.<br />

162


Schlichter, TU München 5.2. EINFÜHRUNG<br />

Anforderung<br />

belegt belegt belegt<br />

belegt belegt belegt<br />

belegt<br />

freie Speicherbereiche<br />

Im Fall eines Anwendungsadressraums tritt dies beim dynamischen Datenbereich<br />

(Halde) auf; Fragmentierung entsteht durch die unterschiedlichen<br />

Speicheranforderungs- und Freigabemuster. Durch zeitaufwendiges Zusammenschieben<br />

der Belegtbereiche (Kompaktifizieren) entsteht aus vielen kleinen<br />

Speicherresten ein großer Freibereich. Beim Kompaktifizieren müssen u.U. die<br />

Adressen in den Programmen angepasst werden (z.B. Verweise auf Absolutadressen).<br />

¯ Interne Fragmentierung<br />

Der Speicher ist in Bereiche fester Größe untergliedert und Speicheranforderungen<br />

werden nur in Vielfachen dieser festen Grundgröße befriedigt.<br />

163


Schlichter, TU München 5.2. EINFÜHRUNG<br />

freier Speicherbereich<br />

Anforderung<br />

Der Verschnitt findet innerhalb dieser Bereiche fester Größe statt. Beispielsweise<br />

kann Plattenspeicher nur blockweise belegt werden; die Blockgröße<br />

schwankt zwischen 512 Byte und 4-8 Kbyte. Selbst für die Speicherung eines<br />

einzigen Bytes muss ein ganzer Block belegt werden.<br />

5.2.4 Forderungen an Adressraumrealisierung<br />

Aus der Sicht der Anwendungsprogrammierung können für einen Adressraum<br />

eine Reihe wichtiger Forderungen an dessen Realisierung gestellt werden.<br />

Hier geht es um den Programmieradressraum für Prozesse, und nicht um den<br />

Maschinenadressraum (Arbeitsspeicher).<br />

¯ Homogene und zusammenhängende Adressbereiche. Dies ermöglicht eine<br />

Programmentwicklung ohne das ansonsten notwendige Wissen über Position,<br />

Typ und Größe der referenzierbaren Speichermodule und E/A-Controller.<br />

¯ Größe des genutzten Adressraums unabhängig von der Kapazität des<br />

physischen Adressraums (Arbeitsspeichers).<br />

¯ Erkennen fehlerhafter Zugriffe.<br />

¯ Erkennen von Überschneidungen zwischen Halde und Keller sowie zwischen<br />

mehreren Laufzeitkellern.<br />

164


Schlichter, TU München 5.3. SPEICHERABBILDUNGEN<br />

¯ Schutz funktionstüchtiger Anwendungen gegenüber fehlerhaften Anwendungen.<br />

Hier geht es darum, dass die Adressbereiche der Anwendungen und auch<br />

des Betriebssystems voneinander abgeschottet werden. Ist dieser Schutz nicht<br />

gewährleistet, können fehlerhafte Programme den Adressraum einer anderen<br />

Anwendung verändern und damit Folgefehler in dieser auslösen nicht deterministische<br />

Fehler. Fehler dieser Art sind schwer zu reproduzieren und ihre<br />

Lokalisierung ist meist extrem schwierig und langwierig.<br />

¯ Kontrollierbares und kontrolliertes Aufteilen der Speicherressourcen auf alle<br />

Anwendungen.<br />

¯ Speicherökonomie, minimale Fragmentierung. Es sollten gängige Techniken<br />

eingesetzt werden, um die durch dynamische Anforderungen bedingte Speicherfragmentierung<br />

und den tatsächlichen Speicherbedarf jeder Anwendung<br />

zu minimieren, z.B. gemeinsame Nutzung von Funktionsbibliotheken durch<br />

mehrere parallel laufende Anwendungen Funktionsbibliothek muss nur einmal<br />

geladen werden.<br />

5.3 Speicherabbildungen<br />

Dieser Abschnitt behandelt einige Mechanismen zur Abbildung von Programmadressen<br />

auf Maschinenadressen des Arbeitsspeichers.<br />

5.3.1 Direkte Adressierung<br />

Bei der direkten Adressierung werden die Programmadressen direkt als<br />

Maschinenadressen interpretiert. Es treten drei Probleme auf:<br />

Verschiebbarkeit,<br />

Programmgröße,<br />

Speicherausnutzung.<br />

Verschiebbarkeit<br />

In einem Mehrprozesssystem sind i.d.R. mehrere Programme im Arbeitsspeicher.<br />

Bei direkter Adressierung werden die Programme beim Laden fixiert und müssen<br />

dann bis zu ihrem Ende an derselben Stelle bleiben. Eine Verschiebung<br />

ist nicht möglich, da der Benutzer mit Adressen rechnen kann und deshalb<br />

positionsabhängige Adressen in seinen lokalen Variablen hat.<br />

165


Schlichter, TU München 5.3. SPEICHERABBILDUNGEN<br />

¯ Problem<br />

Externe Fragmentierung des Arbeitsspeichers. Sei der Arbeitsspeicher zunächst<br />

lückenlos mit Programmen P1, P2, P3 gefüllt.<br />

P1 P2 P3<br />

Nach Beendigung des Programms P2 entsteht eine Lücke.<br />

Neue Programme passen u.U. nicht exakt in die zurückgebliebene Lücke.<br />

Auf diese Weise entstehen immer mehr Lücken. Möglicherweise passen<br />

Programme nicht mehr in den Arbeitsspeicher, weil keine ausreichend große<br />

Lücken vorhanden ist, obwohl insgesamt noch ausreichend Platz wäre. Dies<br />

ist das Problem der externen Fragmentierung des Arbeitsspeichers. Da die<br />

Programme wegen der direkten Adressen nicht verschiebbar sind, ist eine<br />

Speicherbereinigung erst möglich, nachdem alle angefangenen Programme<br />

beendet sind.<br />

Ein verwandtes Problem tritt bei Programmverdrängungen auf. Das verdrängte<br />

Programm muss zur weiteren Ausführung später wieder an dieselbe Stelle<br />

geladen werden, dies ist jedoch in der Regel nicht mehr möglich, da andere<br />

Programme im benötigten Speicherbereich stehen können.<br />

¯ Forderung<br />

In Mehrprogramme/Mehrprozesssystemen müssen daher Programme verschiebbar<br />

sein.<br />

Programmgröße<br />

Programme können wesentlich größer als der verfügbare Arbeitsspeicher werden.<br />

Bei direkter Adressierung muss der Benutzer sein Programm selbst in Segmente<br />

zerlegen und diese nach Bedarf selbst nachladen. Man spricht von der<br />

sogenannten Overlay-Technik (veraltet). Die Overlay-Technik ist aufwendig,<br />

schwierig und damit auch fehleranfällig. Da die Zerlegung statisch ist, kann<br />

die Zerlegung des Programms nicht dynamisch an den konkret vorhandenen<br />

Arbeitsspeicher angepasst werden und damit die jeweilige Maschine gut<br />

ausnutzen.<br />

¯ Forderung<br />

Es muss daher gefordert werden, dass die Programmgröße unabhängig von der<br />

realen Arbeitsspeichergröße ist.<br />

166


Schlichter, TU München 5.3. SPEICHERABBILDUNGEN<br />

Speicherausnutzung<br />

Programme bestehen aus Modulen, die nur zu bestimmten Zeiten verwendet<br />

werden. Beispielsweise wird bei einer Matrizenmultiplikation nur auf die Module,<br />

die das Multiplikationsprogramm und auf die Module, die die Daten enthalten,<br />

zugegriffen. Es ist nun wünschenswert, von einem Programm nur den Ausschnitt<br />

im Arbeitsspeicher zu halten, der momentan und in naher Zukunft benötigt wird.<br />

Damit lassen sich mehr Programme im Arbeitsspeicher unterbringen und parallel<br />

verarbeiten. Dies steigert den Datendurchsatz des Systems.<br />

¯ Forderung<br />

Arbeitsspeicher beinhaltet nur die momentan bzw. in naher Zukunft<br />

notwendigen Ausschnitte des Programms. Nutzen der Lokalitätseigenschaft<br />

von Programmen:<br />

durch Datenstrukturen z.B. Arrays, oder<br />

Programmstrukturen: Prozeduren, Schleifen.<br />

5.3.2 Basisadressierung<br />

Die Basisadressierung hat eine einfache Abbildungsvorschrift:<br />

Maschinenadresse = Basisadresse + Programmadresse<br />

¯ Die Basisadresse ist programmspezifisch. Sie steht in einem Register des<br />

Rechnerkerns und ist dem Programm, das im Benutzermodus abläuft, nicht<br />

zugänglich. Sie wird vom Betriebssystem festgelegt.<br />

¯ Die Programmadressen aller Programme beginnen jeweils mit Null. Durch die<br />

Basisadressierung wird das Problem der Verschiebbarkeit gelöst. Die anderen<br />

Probleme bestehen jedoch weiterhin. Deshalb wird die Basisadressierung in<br />

modernen Betriebssystemen nicht mehr eingesetzt.<br />

¯ Speicherverwaltungsstrategien<br />

Aufgabe: Finden eines zusammenhängenden Arbeitsspeicherbereichs, der groß<br />

genug ist, um das Programm zu speichern. Mögliche Strategien (siehe<br />

Seite 57) werden hier nur angerissen. Hier kommen die Strategien zum Einsatz,<br />

die bereits bei der Haldenverwaltung diskutiert wurden, insbesondere deren<br />

Vor- und Nachteile. Beispielsweise erfordert best-fit immer den Durchlauf<br />

durch die gesamte Freibereichsliste. Zusätzlich liefert diese Strategie mit der<br />

Zeit immer kleinere Fragmente externe Fragmentierung.<br />

167


Schlichter, TU München 5.4. VIRTUELLER SPEICHER<br />

– first-fit<br />

Durchsuche die Liste der Freibereiche vom Anfang an und nimm den ersten<br />

passenden Frei-Bereich: Spalte nicht benötigten Speicher ab und füge ihn als<br />

freien Bereich in die Freibereichsliste ein.<br />

– best-fit<br />

Durchsuche die Liste der Freibereiche vom Anfang an und nimm den<br />

passenden Frei-Bereich, der die Speicheranforderungen des Programms am<br />

besten erfüllt: Spalte nicht benötigten Speicher ab und füge ihn als freien<br />

Bereich in die Freibereichsliste ein.<br />

– worst-fit<br />

Durchsuche die Liste der Freibereiche vom Anfang an und nimm den Frei-<br />

Bereich, der die Speicheranforderungen des Programms am schlechtesten<br />

erfüllt: Spalte nicht benötigten Speicher ab und füge ihn als freien Bereich in<br />

die Freibereichsliste ein.<br />

5.4 Virtueller Speicher<br />

Die virtuelle Adressierung wurde Ende der 50er Jahre eingeführt. Viele<br />

weiterführende Arbeiten erfolgten dann später im Rahmen des Projektes MAC<br />

und des Systems MULTICS (Vorgänger von UNIX) in den USA in den 60er<br />

Jahren. Ziel ist<br />

Virtualisierung des Speichers,<br />

Verstecken von realen Beschränkungen, wie Speichergröße,<br />

Speicher als sehr großes Feld gleichartiger Speicherzellen zu betrachten.<br />

Die Seitenadressierung ("paging") ist die Grundform der virtuellen Adressierung.<br />

5.4.1 Seitenadressierung<br />

Ansatz<br />

Der Programmadressraum, der sogenannte virtuelle Adressraum eines Prozesses<br />

wird in aufeinanderfolgende Seiten (engl. page) gleicher Größe unterteilt.<br />

Man spricht deshalb von virtuellen Adressen des Prozesses, anstatt von<br />

seinen Programmadressen. Gängige Größen für virtuelle Adressräume heutiger<br />

Architekturen:<br />

2 32 , also 32-Bit Adressen zum Ansprechen der Speicherzellen.<br />

Fortgeschrittene Architekturen: 2 64 , also 64-Bit Adressen (z.B. Sun ULTRA-<br />

Sparc).<br />

168


Schlichter, TU München 5.4. VIRTUELLER SPEICHER<br />

Die Seiten sind keine logische Aufteilung des Speichers. Denkaufgabe: was hat<br />

das für Vor- und Nachteile?<br />

¯ Der Maschinenadressraum, also der physische Adressraum des Arbeitsspeichers,<br />

wird in Kacheln (engl. frame) unterteilt. Seiten und Kacheln sind i.d.R.<br />

gleich groß. Es ist auch möglich, dass die Seitengröße ist ein Vielfaches der<br />

Kachelgröße ist. Im Folgenden wird von gleichen Größen ausgegangen. Für<br />

die MI ist als Kachelgröße 512 Byte festgelegt. Dies ist für heutige Architekturen<br />

zu klein (eher4-8KByte).<br />

¯ Eigenschaften der Seitenadressierung<br />

– Die Seiten eines Prozesses können im Arbeitsspeicher oder auf dem<br />

Hintergrundspeicher (Platte) gespeichert sein.<br />

– Die Kacheln nehmen die Seiten der Prozesse auf. Wichtig ist, dass sowohl<br />

die Seiten als auch die sie aufnehmenden Container, die Kacheln, eine<br />

einheitliche Größe besitzen. Das erleichtert die Speicherverwaltungsaufgabe<br />

erheblich.<br />

– Wenn während der Prozessausführung eine virtuelle Adresse des Prozessadressraums<br />

verwendet wird, so muss die Seite, in der sich die Adresse<br />

befindet, in einer Kachel des Arbeitsspeichers geladen (eingelagert) sein. Es<br />

ist eine Abbildungsvorschrift notwendig, die die virtuelle Adresse auf die<br />

reale Kacheladresse (Maschinenadresse) abbildet. Ein Problem ist:<br />

woher weiss das BS welche Seite eines Prozesses sich wo im<br />

Arbeitsspeicher befindet, d.h. welche Kachel welcher Seite zugeordnet<br />

ist?<br />

Antwort: Beschreibung der Seiten erforderlich; dazu Verwendung von<br />

Deskriptoren, die in Tabellen verwaltet werden (Seiten-Kacheltabelle).<br />

– Die Zuordnung, welche Seite in welcher Kachel gespeichert ist, und wo sich<br />

die Seite auf dem Hintergrundspeicher befindet, erfolgt mittels der Seiten-<br />

Kacheltabelle, die die Seitendeskriptoren enthält. Die Zuordnung von Seite<br />

zu Kachel kann sich im Laufe eines Programmablaufes ändern.<br />

– Befindet sich bei einer Befehlsausführung die erforderliche Seite nicht im<br />

Arbeitsspeicher, so löst ein solcher Zugriff eine Unterbrechung aus<br />

Seitenfehler Einlagerung der Seite bei Bedarf ("Demand Paging"). Der<br />

Seitenfehler ist eine synchrone Unterbrechung, die vom Betriebssystem zu<br />

behandeln ist, d.h. die geforderte Seite ist in den Arbeitsspeicher zu laden.<br />

Man spricht deshalb auch vom Demand Paging. Nach dem erfolgreichen<br />

Laden der Seite wird der Befehl, der zum Alarm führte, erneut ausgeführt.<br />

Der gesamte Vorgang heißt Seiteneinlagerung (engl. paging).<br />

169


Schlichter, TU München 5.4. VIRTUELLER SPEICHER<br />

– Falls eine Seite eingelagert werden muss, aber gleichzeitig bereits alle<br />

Kacheln des Arbeitsspeichers besetzt sind, so muss eine der eingelagerten<br />

Seiten aus dem Arbeitsspeicher verdrängt werden. Man spricht von<br />

der Seitenauslagerung. Die Strategien, die man hierbei einsetzt, heißen<br />

Seitenersetzungsstrategien. Ziel dieser Strategien ist es, eine möglichst<br />

günstige Seite auszuwählen, und diese auf den Hintergrundspeicher<br />

auszulagern. Günstig bedeutet hier, eine Seite, die entweder für den<br />

Prozessablauf nicht mehr benötigt wird, oder die erst sehr viel später benötigt<br />

wird, als die anderen Seiten im Arbeitsspeicher.<br />

¯ virtueller Speicher - Arbeitsspeicher<br />

Der Zusammenhang zwischen dem virtuellen Speicher, hier den virtuellen<br />

Adressräumen der Prozesse, und dem Arbeitsspeicher sowie Hintergrundspeichermedien<br />

wird nachfolgend skizziert. Auf die einzelnen Bereiche gehen wir<br />

im Folgenden näher ein. Wir gehen hier vereinfachend davon aus, dass auch die<br />

Blöcke als Einheiten des Hintergrundspeichers die Größe einer Seite besitzen.<br />

virt. Adressraum von P1<br />

Seite 1 von<br />

P1<br />

Seite 2 von<br />

P1<br />

.....<br />

Seite 1 von<br />

P2<br />

Seite 2 von<br />

P2<br />

.....<br />

virt. Adressraum von P2<br />

Seiten-Kachel<br />

Tabelle<br />

...<br />

...<br />

...<br />

...<br />

...<br />

...<br />

...<br />

...<br />

Deskriptor<br />

Kachel 1<br />

Kachel 2<br />

Kachel 3<br />

Kachel 4<br />

Kachel 5<br />

...<br />

Arbeitsspeicher<br />

mit Kacheln<br />

Auslagern<br />

Einlagern<br />

Hintergrundspeicher<br />

mit Blöcken<br />

¯ Vorteile<br />

Bei der Seitenadressierung werden durch eine flexible Speicherabbildung alle<br />

Probleme der direkten Adressierung (siehe Seite 165) gelöst.<br />

Programme können:<br />

verschoben werden,<br />

größer als der Arbeitsspeicher sein,<br />

auch ausschnittsweise im Arbeitsspeicher sein.<br />

D.h. die<br />

170


Schlichter, TU München 5.4. VIRTUELLER SPEICHER<br />

– Zusätzliche positive Eigenschaften<br />

£ Es können gemeinsame Speicherbereiche zwischen Prozessen realisiert<br />

werden. Programme können gemeinsame Speicherbereiche haben,<br />

beispielsweise bei gemeinsamen Daten nebenläufiger Prozesse. Auch<br />

Code-Bereiche können im Hinblick auf eine bessere Speicherausnutzung<br />

gemeinsam sein, beispielsweise muss der Code eines Compilers nur<br />

einmal geladen werden, auch wenn ihn mehrere Benutzer gleichzeitig<br />

verwenden.<br />

£ Es ist ein differenzierter Zugriffsschutz innerhalb eines Prozesses möglich.<br />

Zugriffsrechte für einzelne Seiten können unterschiedlich vergeben<br />

werden.<br />

Adressabbildung<br />

Bei der Seitenadressierung erfolgt die Umsetzung der Programmadressen, also die<br />

Umsetzung der virtuellen Adressen in Maschinenadressen durch eine Abbildung<br />

von Seiten auf Kacheln. Eine virtuelle Adresse v ist gegeben durch v = (s, w),<br />

wobei s die Seitennummer und w das Offset in der Seite angibt. Die Adresse<br />

v wird abgebildet auf die reale Adresse p = (k, w), wobei k die Kachelnummer<br />

angibt, die die Seite enthält.<br />

Seitentabellenregister<br />

Längenregister<br />

L<br />

Seiten-Kacheltabelle<br />

k<br />

s<br />

virtuelle Adresse<br />

s w<br />

k w<br />

Adresse im Arbeitsspeicher<br />

Die Adressrechnung wird von der Hardware, der MMU (Memory Management<br />

Unit), durchgeführt. D.h. die virtuelle Adresse wird von der CPU nicht direkt<br />

auf den Speicherbus gelegt, sondern an die MMU (Chip oder mehrere Chips)<br />

weitergeleitet. Die MMU berechnet die reale Adresse und legt sie auf den Bus.<br />

Falls s L ist, kann mit Hilfe des Längenregisters sofort ein Adressierungsfehler<br />

171


Schlichter, TU München 5.4. VIRTUELLER SPEICHER<br />

entdeckt werden.<br />

¯ Beispiel für Adressrechnung<br />

Gegeben sei ein 16-Bit virtueller Adressraum und eine Seitengröße von 4K.<br />

D.h. der Adressraum zerfällt in 16 Seiten; man benötigt 4 Bit, um die<br />

Seitennummern zu identifizieren und 12-Bit, um die 4096 Byte innerhalb<br />

einer Seite zu adressieren. Die Anzahl der Bits von s (Seitennummer) und k<br />

(Kachelnummer) können sich unterscheiden. Die Zahl der Bits von s hängt von<br />

der Größe des virtuellen Adressraums ab, während sich die Anzahl der Bits<br />

von k aus der Größe des Maschinenadressraums ergibt. Damit können s und k<br />

unterschiedliche lang sein.<br />

v = 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0<br />

s = 2<br />

p =<br />

present/<br />

absent Bit<br />

0 010 1<br />

1 001 1<br />

2 110 1<br />

3 000 1<br />

4 100 1<br />

5 011 1<br />

6 000 0<br />

7 000 0<br />

8 000 0<br />

9 101 1<br />

10 000 0<br />

11 111 1<br />

12 000 0<br />

13 000 0<br />

14 000 0<br />

15 000 0<br />

Seiten-<br />

Kacheltabelle<br />

12 bit offset w<br />

wird kopiert<br />

1 1 0 0 0 0 0 0 0 0 0 0 1 0 0<br />

k = 6<br />

172


Schlichter, TU München 5.4. VIRTUELLER SPEICHER<br />

Seiten-Kacheltabelle<br />

Die Adressabbildung erfolgt mittels der Seiten-Kacheltabelle (SKT). D.h.<br />

wir benötigen Informationen über die zu verwaltenden Seiten. Dazu wird<br />

jede Seite eines Prozesses durch einen Seitendeskriptor beschrieben. Die<br />

Seiten-Kacheltabelle ist i.a. prozessspezifisch. Neben der Zuordnung Seite-<br />

Kachel enthält ein Seitendeskriptor noch weitere Informationen, wie z.B. die<br />

Zugriffsrechte und den Zustand der Seite.<br />

¯ Struktur eines Seitendeskriptor<br />

Informationen in einem Seitendeskriptor:<br />

– Zugriffsrechte (R)<br />

Angabe, ob der Prozess<br />

- ausführend (x R),<br />

- lesend (r R),<br />

- schreibend (s R).<br />

auf die Seite zugreifen darf. Diese Information wird vom Betriebssystem<br />

eingetragen und im Rechnerkern vor dem Zugriff ausgewertet.<br />

– Seite existent (e)<br />

Es müssen nicht alle Seiten existent sein. Beispielsweise sind oft die<br />

Seiten zwischen Ende der Halde und Kellerende nicht existent. Generell<br />

besteht die Vorstellung, dass in einem Adressraum mehrere Objekte (Daten<br />

oder Programmteile) sind, zwischen denen Lücken liegen können. Seiten<br />

des Adressraums, in denen keine Objekte sind, sind nicht existent. Wird<br />

versucht, auf eine nicht existente Seite zuzugreifen, dann gibt es einen<br />

Speicherschutzalarm.<br />

– Seite geladen (v)<br />

Die Abbildung ist gültig (engl. valid ). Die Seite ist also in den<br />

Arbeitsspeicher geladen, d.h. ihr ist eine Kachel zugeordnet. Es kann auf<br />

sie zugegriffen werden. Eine nicht geladene, aber existente Seite steht im<br />

Verdrängungsbereich (engl. swap area) auf dem Plattenspeicher. Soll auf<br />

eine existente, aber nicht geladene Seite zugegriffen werden, dann löst die<br />

CPU einen Seitefehltalarm aus, d.h. ein Seitenfehler tritt ein. Die Seite<br />

wird vom Hintergrundspeicher geladen, und das Programm an der Stelle<br />

fortgesetzt, die den Seitefehltalarm auslöste.<br />

– Zugriffsbit (z)<br />

Das Zugriffsbit (engl. reference bit) dient zur Unterstützung der<br />

Seitenersetzungsalgorithmen. Es wird von der CPU nach dem Laden der<br />

Seite gelöscht und bei einem Zugriff auf eine Seite von der CPU gesetzt.<br />

173


Schlichter, TU München 5.4. VIRTUELLER SPEICHER<br />

– Veränderungsbit (m)<br />

Die Seite wurde verändert (modifiziert). Dieses Bit dient ebenfalls zur<br />

Unterstützung der Seitenersetzungsalgorithmen. Es wird nach dem Laden<br />

der Seite von der CPU gelöscht und nach einem schreibenden Zugriff auf die<br />

Seite gesetzt. Beispielsweise könnte eine Verdrängungsstrategie bevorzugt<br />

Seiten auslagern, die nicht modifiziert wurden, d.h. ein Übertragen der<br />

Seite auf den Hintergrundspeicher ist nicht notwendig, da die Seite auf dem<br />

Hintergrundspeicher noch aktuell ist man spart sich den Datentransfer.<br />

¯ Probleme<br />

Es gibt einige Probleme mit der Seitenadressierung, die sich auf die<br />

Speichereffizienz und die Performanz beziehen.<br />

– Größe der Seiten-Kacheltabelle<br />

Die Seiten-Kacheltabelle kann sehr groß werden, z.B. bei Seitengröße 4K<br />

(früher üblich!) ergeben sich für 32-bit Adressraum insgesamt 1 Million<br />

Seiten pro Prozess.<br />

Lösung? Mehrstufige Tabellen: Seiten-Kacheltabelle ebenfalls in Seiten<br />

unterteilen, die ihrerseits in Tabellen gehalten werden. Technisch wird<br />

bei einem mehrstufigen Verfahren der Seitenanteil der virtuellen Adresse<br />

in Abhängigkeit von der Stufenzahl weiter unterteilt, z.B. s1, s2,...sn.<br />

In der Regel wird mit der Adressabbildung ab dem höchstwertigen Bit<br />

begonnen. Der Anteil s1 definiert den Index für die Seitentabelle erster<br />

Stufe, s2 den Index für den Anteil zweiter Stufe, etc.<br />

virtuelle Adresse<br />

s1 s2 w<br />

Deskriptor<br />

Deskriptor k w<br />

174


Schlichter, TU München 5.4. VIRTUELLER SPEICHER<br />

Beispielsweise kann ein 32-Bit Adressraum auf der ersten Stufe in 128<br />

Seiten (2 7 ) mit je 32 MByte unterteilt werden. Ein Seitentabellen-Deskriptor<br />

verweist auf eine Seitentabelle, die die 32 MByte große Seite in weitere<br />

Seiten unterteilt, z.B. 256 KByte. Es muss nicht die gesamte Tabelle im<br />

Arbeitsspeicher gehalten werden. Das schrittweise Durchlaufen u. U.<br />

mehrstufiger Seiten-Kacheltabellen nennt man Page-Table Lookup.<br />

– Performanz<br />

Schnelle Umrechnung der virtuellen auf realen Adressen erforderlich, da<br />

Berechnung bei jedem Zugriff notwendig ist! Häufig verwendete Adressen<br />

werden in einem Schnellzugriffspeicher (cache) der MMU gehalten, dem<br />

Translation Lookaside Buffer (TLB). Bei jedem Zugriff auf eine virtuelle<br />

Adresse wird überprüft, ob sich die zugehörige Seite und damit die<br />

Kacheladresse im TLB befindet. TLB ist als assoziativer Cache organisiert<br />

(vgl.TGI!), d.h. alle Einträge werden gleichzeitig auf Übereinstimmung<br />

mit dem Seitenanteil der referenzierten Adresse verglichen. Ist kein<br />

entsprechender Eintrag in der TLB, erfolgt die Adressabbildung über den<br />

relevanten Deskriptor der Seiten-Kacheltabelle. Idee ist, dass der TLB<br />

wenige Einträge enthält (ca. 8). Ein Eintrag enthält eine virtuelle und<br />

zugeordnete reale Adresse kein aufwändiges Page Table Lookup für TLB-<br />

Einträge erforderlich. Designziel bei der Verwaltung der TLB-Einträge ist<br />

eine gute Trefferrate (cache hit).<br />

¯ Varianten der SKT<br />

Varianten für den Aufbau einer Seiten-Kacheltabelle.<br />

– Prozess-spezifisch, Index-basiert (PI)<br />

Zugriff auf Deskriptor für Seite s über Index i.<br />

i<br />

– Prozess-spezifisch, assoziativ (PA)<br />

Hier wird die Seitennummer mit in den Seitendeskriptor aufgenommen. Die<br />

SKT ist prozessspezifisch. Es sind nur die geladenen Seiten aufgeführt.<br />

– Global, assoziativ (GA)<br />

Es gibt nur eine SKT im System. Da die Seitennummer allein nicht eindeutig<br />

ist, muss das Prozesskennzeichen (PID), d.h. der eindeutige Prozessname,<br />

ebenfalls in den Deskriptor aufgenommen werden. Es sind nur die geladenen<br />

Seiten aufgeführt. Die maximale Anzahl der Elemente dieser SKT ist die<br />

Anzahl der Kacheln, falls gemeinsame Speicherbereiche der Prozesse nicht<br />

betrachtet werden.<br />

– Global, indiziert (GI)<br />

175


Schlichter, TU München 5.4. VIRTUELLER SPEICHER<br />

Enthält auch PID und es erfolgt eine Reihung gemäß der Kachelnummer;<br />

freie Kacheln werden durch einen speziellen Eintrag gekennzeichnet.<br />

Kacheln, denen keine Seite zugeordnet ist, erhalten einen speziellen Eintrag<br />

bei PID. Damit enthält die Tabelle so viele Elemente wie Kacheln im<br />

Arbeitsspeicher vorhanden sind. Da die Angabe der Kachelnummern sich<br />

aus der Position in der Tabelle ergibt, kann diese Angabe entfallen.<br />

Seitenfehlerbehandlung<br />

Der Zugriff auf eine Seite, die nicht im Arbeitsspeicher ist, führt zu einem<br />

Seitenfehler.<br />

load M<br />

Prozess P1<br />

(1) Zugriff<br />

(6) Befehl<br />

erneuert<br />

Seiten-<br />

Kacheltabelle<br />

(2) page fault<br />

Seitenfehlerbehandlung<br />

des<br />

BS<br />

Ablauf der Seitenfehlerbehandlung<br />

(5) Aktualisieren<br />

Arbeitsspeicher<br />

Kachel 1<br />

Kachel 2<br />

Kachel 3<br />

.....<br />

(3) Seite auf Hintergrundspeicher<br />

(4) Einlagern<br />

Hintergrundspeicher<br />

mit Blöcken<br />

1. Beim Zugriff auf eine virtuelle Adresse (z.B. LOAD-Befehl) tritt ein<br />

Seitenfehler auf.<br />

2. Die Adressrechnungshardware löst einen Alarm aus, so dass die Unterbrechungsbehandlung<br />

des BS aktiviert wird. Dieser wird beispielsweise in der<br />

MMU bei der Adressrechnung ausgelöst. Der Prozesszustand muss gerettet<br />

werden, u.a. der Befehlszähler und die Registerbelegungen. Weiterhin muss<br />

der Unterbrechungsbehandlung die Adresse übergeben werden, die den Seitenfehler<br />

auslöste.<br />

3. Das BS stellt eine freie Kachel zur Verfügung, lokalisiert die Seite auf der Platte<br />

und initiiert die Einlagerung der Seite (Lesen von Platte). Falls aktuell keine<br />

Kachel frei ist, muss eine Seite auf den Hintergrundspeicher verdrängt werden.<br />

4. Die Seite wird eingelagert.<br />

176


Schlichter, TU München 5.4. VIRTUELLER SPEICHER<br />

5. Der Seitendeskriptor wird aktualisiert und verweist jetzt auf die belegte Kachel<br />

(im Beispiel k = 3).<br />

6. Der unterbrochene Befehl wird erneut gestartet. Die Daten sind jetzt<br />

zugreifbar. Dazu muss zunächst wieder der Prozesszustand geladen werden,<br />

d.h. Befehlszähler, Register etc. Anschließend wird der Befehl fortgeführt, als<br />

ob keine Unterbrechung stattgefunden hätte.<br />

Seitenverwaltungsstrategien<br />

Aufgabe der Arbeitsspeicherverwaltung: Laden der für die Ausführung der<br />

Prozesse benötigten Seiten in die Kacheln. Es ergeben sich drei strategische<br />

Aufgaben:<br />

¯ Ladestrategie<br />

Frage: welche Seite ist zu Laden?<br />

– Lösungsansätze<br />

£ Einzelseitenanforderungsstrategie (on demand): eine Seite wird genau<br />

dann geladen, wenn auf sie zugegriffen wird und sie sich noch nicht im<br />

Arbeitsspeicher befindet.<br />

£ Seiten-Prefetching: Seiten werden im Voraus geladen, um sie sofort bei<br />

Bedarf verfügbar zu haben. Wann ist Prefetching sinnvoll und was benötigt<br />

das BS? Beispielsweise am Anfang beim Laden des main-Programms.<br />

¯ Platzierungsstrategie<br />

Frage: in welche Kachel ist eine Seite zu Laden?<br />

– Lösung<br />

£ keine strategische Entscheidung erforderlich, da alle Kacheln gleichwertig<br />

sind und damit keine Auswahl getroffen werden muss. Vorteil der<br />

uniformen Realisierungskonzepte (Seite, Kachel).<br />

¯ Seitenverdrängungsstrategie<br />

Frage: welche Seite ist aus dem Arbeitsspeicher zu entfernen, wenn für eine zu<br />

ladende Seite keine freie Kachel mehr zur Verfügung steht? Im Idealfall baut<br />

ein Verdrängungsverfahren auf der Referenzlokalität vieler Programme und<br />

der sich ergebenden Lokalitätsmenge auf. Solange sich die Lokalitätsmenge<br />

jedes Prozesses im Arbeitsspeicher befindet, ist die Seitenfehlerrate sehr<br />

177


Schlichter, TU München 5.4. VIRTUELLER SPEICHER<br />

gering. Auf der Grundlage der Working-Set-Theorie ergibt sich damit<br />

für ein Seitenverdrängungsverfahren die Aufgabe, bevorzugt solche Seiten<br />

auszulagern, die nicht in der Lokalitätsmenge enthalten sind.<br />

– Strategien<br />

£ FIFO (first-in first-out): Verdrängen der ältesten Seite, einfach zu<br />

implementieren. Das Verfahren berücksichtigt die Lokalitätsmenge<br />

nicht. So werden über längere Zeit hinweg häufig referenzierte Seiten<br />

verdrängt. Umgekehrt bleiben auch wenig referenzierte Seiten im<br />

Mittel genauso lange im Arbeitsspeicher wie häufig referenzierte Seite.<br />

Vorsicht bzgl der FIFO-Anomalie, d.h. trotz Vergrössern des zur<br />

Verfügung stehenden Arbeitsspeichers können u.U. mehr Seitenfehler<br />

(d.h. Seiteneinlagerungsoperationen) auftreten, als bei kleinerem<br />

Speicher. (Warum, woran könnte so etwas liegen? Antwort: FIFO beachtet<br />

nicht, wann die Seite zuletzt benutzt wurde. D.h. eine häufig benutzte<br />

globale Variable, die zu einem frühen Zeitpunkt eingelagert wurde, könnte<br />

z.B. dazu führen, dass diese Seite nach dem Entfernen gleich wieder<br />

eingelagert werden muss.)<br />

£ LIFO (last-in first-out): Verdrängen der jüngsten Seite, einfach zu<br />

implementieren. Diese Strategie berücksichtigt Lokalitätseigenschaft von<br />

Programmen (häufig in Schleifen, Prozeduren Zugriff auf gleiche<br />

Seiten) nicht.<br />

£ LRU (Least recently used): Verdrängen der am längsten nicht genutzten<br />

Seite; wird am häufigsten realisiert, wobei LRU approximiert wird, da<br />

eine exakte Realisierung zu aufwendig ist. Eine exakte Realisierung ist<br />

durch spezielle Hardware möglich, die jeder Seite ein Zeitfeld assoziiert<br />

und dieses bei jedem Zugriff aktualisiert.<br />

Frage: wie LRU-Verhalten approximieren<br />

Antwort: Nutzen eines Referenz-Bits (siehe R-<br />

Bit der Seitendeskriptor-Informationen) pro Seite, das durch Hardware<br />

bei einem Seitenzugriff gesetzt wird. Jeder Seite wird ein Zähler zugeordnet.<br />

Das BS inspiziert in regelmäßigen Abständen die Seiten, und<br />

inkrementiert den Zähler der Seiten mit nicht gesetztem Bit. Für jede<br />

referenzierte Seite werden dagegen Zähler und R-Bit gelöscht. Verdrängt<br />

wird immer die Seite mit dem höchsten Zählerstand, da diese<br />

am längsten nicht referenziert wurde.<br />

Andere Alternativen sind z.B. Second Chance.<br />

£ Optimale Strategie: Seite, auf die in Zukunft am längsten nicht<br />

zugegriffen wird; die optimale Strategie ist unrealistisch, da das zukünftige<br />

Verhalten i.d.R. nicht bekannt ist. Leistungsdaten dieser Strategie,<br />

178


Schlichter, TU München 5.4. VIRTUELLER SPEICHER<br />

d.h. wieviele Seitenfehler treten bei gegebener Arbeitsspeichergröße und<br />

gegebenen Zugriffscharakteristika von Prozessen auf, gibt Obergrenze für<br />

Erreichbares an.<br />

¯ Weitere offene Fragen<br />

– Wahl einer vernünftigen Seitengröße<br />

Die Wahl der Seitengröße steht unter widersprüchlichen Zielsetzungen;<br />

daher ist ein Kompromiss erforderlich.<br />

1. Je kleiner die Seite, desto rascher die Transfers zwischen ASP und<br />

Platte.<br />

2. Je kleiner die Seite, desto geringer der Verschnitt (interne<br />

Fragmentierung) durch nicht voll ausgenützte Seiten.<br />

3. Je größer die Seite, desto geringer der Overhead für Transport<br />

zwischen Arbeitsspeicher und Platte pro Byte (Arm positionieren,<br />

Warten bis Spur unter Lese-Schreib-Kopf).<br />

4. Je größer die Seite, desto mehr Information kann zwischen<br />

Arbeitsspeicher und Platte je Zeiteinheit transportiert werden.<br />

5. Je größer die Seite, desto seltener Transfers erforderlich.<br />

£ Beispiele für Seitengrößen: Intel 80386 4K, Pentium II 4K oder 4MB,<br />

UltraSPARC 8K, 64K, 512K oder 4MB. Tendenz: grössere Seiten.<br />

Warum? schnelle CPU und großer Arbeitsspeicher, Seitenfehler haben<br />

großen Einfluss auf Performanz des Rechensystems, deshalb möglichst<br />

wenige.<br />

– Seitenflattern<br />

Seitenflattern (engl. thrashing) tritt auf, wenn im System zuviele Prozesse<br />

sind, die nebenläufig voranschreiten wollen und Kacheln beanspruchen.<br />

Gerade verdrängte Seiten müssen zu schnell wieder eingelagert werden, das<br />

System ist im schlimmsten Fall nur noch mit Ein- und Auslagern beschäftigt.<br />

5.4.2 Segment-Seitenadressierung<br />

Unterteilung des Programmadressraums in logische Einheiten unterschiedlicher<br />

Länge, sogenannte Segmente. Ein Segment umfasst inhaltlich bzw. organisatorisch<br />

zusammengehörige Speicherbereiche, z.B. Daten, Code und<br />

Laufzeitkeller-Segment. Im Gegensatz dazu ist die Seiteneinteilung systembedingt<br />

und vom jeweiligen Programm unabhängig.<br />

¯ Jedes Segment besitzt eine maximale Größe. Die Länge der einzelnen<br />

Segmente kann unterschiedlich sein und sich dynamisch verändern.<br />

179


Schlichter, TU München 5.4. VIRTUELLER SPEICHER<br />

¯ Jedes Segment wird durch einen Segment-Deskriptor beschrieben. Die<br />

Segmentdeskriptoren werden in einer Segmenttabelle verwaltet.<br />

¯ Jedes Segment besteht aus Seiten, die jeweils beginnend mit Null fortlaufend<br />

numeriert sind.<br />

¯ Ein Zugriff auf ein nicht existentes Segment führt zum Speicherschutzalarm.<br />

¯ Um in dieser Situation möglichst kompakte Speicherabbildungstabellen zu<br />

erhalten, wird die Seiten-Kacheltabelle aufgeteilt. je Segment eine<br />

eigene Seiten-Kacheltabelle gehalten. Die (Maschinen-) Adressen der Seiten-<br />

Kacheltabellen werden in einer Segmenttabelle gehalten.<br />

Segmenttabellenregister<br />

+<br />

sg<br />

0<br />

sg<br />

s w<br />

Segmenttabelle<br />

Seiten-Kacheltabelle<br />

Adresse im<br />

Arbeitsspeicher<br />

virtuelle Adresse k w<br />

Bei der Adressierung der Tabellen muss natürlich jeder Index mit der Länge eines<br />

Seiten- bzw Segmentdeskriptors (LOP) multipliziert werden. Falls ein Eintrag 4<br />

Byte lang ist, ergibt sich damit z.B.<br />

Adresse des Segmentdeskriptors =<br />

Wert Segmenttabellenregister + sg * 4.<br />

Entsprechendes gilt auch für die Seiten-Kacheltabelle.<br />

5.4.3 Speicherverwaltung der MI<br />

Die Modellmaschine unterstützt neben der direkten Adressierung auch eine<br />

Seitenadressierung ergänzt um drei wohldefinierte Segmente.<br />

180<br />

+<br />

0<br />

s<br />

k


Schlichter, TU München 5.4. VIRTUELLER SPEICHER<br />

virtuelle Adresse<br />

PCS s w<br />

0 1 2 22 23 31<br />

¯ PCS = 0 (P0-Bereich): dieser Bereich enthält das Benutzerprogramm und die<br />

Daten (Halde).<br />

¯ PCS = 1 (P1-Bereich): Bereich des Laufzeitkellers des Benutzerprogramms.<br />

¯ PCS = 2 (Systembereich): dieser Bereich ist in der Regel in allen Prozessen<br />

einheitlich durch die BS-Komponenten belegt, d.h. das BS ist in jedem<br />

Programmadressraum.<br />

¯ PCS = 3: unzulässiger Bereich<br />

181


Kapitel 6<br />

Dateisysteme<br />

Dateisysteme dienen der dauerhaften Speicherung von Programmen und<br />

Daten. Zum Einsatz kommen magnetische und optische Medien, die im<br />

Gegensatz zum Arbeitsspeicher auch nach dem Ausschalten der Rechenanlage<br />

den Datenerhalt sicherstellen. Beispiele von externen Speichermedien sind<br />

Festplatten, Magnetbänder, CD-ROM (wiederbeschreibbar) und neuerdings auch<br />

DVDs. Der schlechten Zugriffszeit externer Speichersysteme (im Vergleich zum<br />

Arbeitsspeicher) steht eine vergleichsweise hohe Kapazität und ein sehr gutes<br />

Preis-Leistungsverhältnis gegenüber. Zentrale Aufgabe des Dateisystems ist es<br />

die besonderen Eigenschaften externer Speichermedien optimal umzusetzen und<br />

Applikationen einen effizienten Zugriff auf die persistent gespeicherten Daten zu<br />

ermöglichen. Es gelten folgende grundlegende Forderungen<br />

a) Speicherung großer Informationsmengen (Video)<br />

b) kein Datenverlust auch bei Prozess- / Systemabsturz<br />

c) nebenläufiger Zugriff durch mehrere Prozesse<br />

Neben Dateisystemen gibt es Datenbanksysteme, die aus einer Menge von<br />

Daten und den zugehörigen Programmen zum Zugriff auf die Daten sowie zur<br />

Kontrolle der Konsistenz bestehen. Der Zugriff auf die Daten erfolgt immer<br />

über Operationen des Datenbanksystems, und nicht direkt durch die einzelnen<br />

Applikationen.<br />

6.1 Fragestellungen<br />

Dieser Abschnitt beschäftigt sich mit den Mechanismen eines Rechensystems zur<br />

dauerhaften (persistenten) Speicherung von Programmen und Daten:<br />

¯ Charakteristika von Dateisystemen.<br />

182


Schlichter, TU München 6.2. CHARAKTERISTIKA VON DATEISYSTEMEN<br />

¯ Schichtenmodell eines Dateisystems.<br />

6.2 Charakteristika von Dateisystemen<br />

Jedes Dateisystem unterstützt 2 grundlegende Abstraktionen:<br />

Datei: Behälter für die persistente Speicherung jeglicher Information.<br />

Information können Daten, der Code ausführbarer Programme, aber auch<br />

kontinuierliche Daten wie Videoströme sein. Das Dateisystem bietet<br />

besondere Zugriffsfunktionen an, die der Zugriffscharakteristik externer<br />

Speicher Rechnung tragen.<br />

Verzeichnisse: spezielle Dateien zur Strukturierung externer Speichermedien.<br />

¯ blockorientierter Datentransfer zwischen externem Speicher und Arbeitsspeicher.<br />

Aufgrund der hohen Zugriffszeiten bei externen Speichermedien ist ein<br />

kleines Lese- und Schreibgranulat nicht sinnvoll. Daher bilden sogenannte<br />

Blöcke die kleinste Übertragungseinheit. Typische Blockgrößen: 512 Byte -<br />

4 KByte. Der Zugriff auf das 1. Byte eines Blocks auf der Festplatte hängt von<br />

der Positioniergeschwindigkeit ab (im Mittel mehrere Millisekunden), während<br />

die Zugriffszeit auf die restlichen Bytes von der Umdrehungsgeschwindigkeit<br />

der Platte abhängt. Zu große Blöcke resultieren in wachsender Information, die<br />

vom Prozess primär nicht angefordert wurde.<br />

¯ Charakteristika der Dateinutzung (empirisch ermittelt):<br />

a) Dateien sind meist klein (wenige KBytes).<br />

b) Dateien werden häufiger gelesen, seltener geschrieben und noch seltener<br />

gelöscht.<br />

c) vornehmlich sequentieller Zugriff.<br />

d) Dateien werden selten von mehreren Programmen oder Personen<br />

gleichzeitig benutzt.<br />

Datei-Zugriffsoperation werden oft gemäß dieser Charakteristika optimiert. Für<br />

Multimedia verändert sich die Nutzungscharakteristik.<br />

große Dateien (mehrere GByte).<br />

gleichmäßige Zugriffsgeschwindigkeit (um Ruckeln zu vermeiden).<br />

notwendige Übertragungsbandbreite. Zum Beispiel ist bei einer unkomprimierten<br />

Videoaufzeichnung im Format 1024*768 bei 3 Byte pro Pixel<br />

und 50 Bildern pro Sekunde eine Übertragungskapazität von 112,5MByte<br />

pro Sekunde notwendig (Datei hat bereits nach einer Minute eine Größe<br />

von 6,5 GByte).<br />

183


Schlichter, TU München 6.3. DATEIEN<br />

6.3 Dateien<br />

Dateien bilden in einem Dateisystem die Behälter für die dauerhafte Speicherung<br />

beliebiger Information. Dabei nutzen nicht nur Benutzerprogramme, sondern<br />

auch die Systemsoftware greift in vielen Fällen auf Dateien zurück. Beispielsweise<br />

wird auch die Auslagerung von Seiten des virtuellen Adressraums über<br />

das Dateisystem auf einer sogenannten Auslagerungsdatei (siehe Windows 9x)<br />

vorgenommen.<br />

¯ in den meisten Systemen wird eine Datei als eine Folge von Bytes aufgefasst.<br />

Eine Datei beginnt mit dem Byte 0 und endet in Abhängigkeit von ihrer Länge<br />

n mit dem Byte n-1.<br />

¯ Dateinamen<br />

in manchen Dateisystemen haben Dateinamen die Form "name.extension".<br />

Beispiele für extension: Ú ØÑÐ Ô ØÜ<br />

Ó ÞÔ<br />

In einigen Betriebssystemen werden die Datei-Extension sematisch interpretiert<br />

und veranlassen ein bestimmtes Verhalten, z.B. ein Doppel-Click auf eine<br />

".doc"-Datei startet Microsoft Word. In Unix sind Datei-Extensions nur<br />

Konventionen. Das Mac Betriebssystem nutzt keine Extensions, um<br />

Applikationen zu triggern; dort wird eine zusätzliche Ressource-Datei genutzt.<br />

¯ Dateiaufbau<br />

Die interne Struktur einer Datei hängt von der jeweiligen Nutzung und<br />

Zielsetzung ab, z.B. ASCII Datei besteht aus Zeilen, die mit CR, LF<br />

abgeschlossen sind. MS-DOS verwendet eine Kombination von CR und LF.<br />

Beispiel einer Archivdatei<br />

184


Schlichter, TU München 6.3. DATEIEN<br />

Header<br />

Objekt Modul<br />

Header<br />

Objekt Modul<br />

Header<br />

Objekt Modul<br />

Modulname<br />

Datum<br />

Owner<br />

Zugriffsrechte<br />

Länge<br />

Ein weiteres Beispiel haben wir bereits beim Aufbau des Objektprogramms<br />

(siehe Seite 39) für die MI kennengelernt.<br />

¯ Operationen<br />

Dateisysteme unterstützen die folgenden grundlegenden Systemaufrufe:<br />

ÓÔÒ<br />

Öffnen einer Datei; Ergebnis ist ein Dateideskriptor, über den in<br />

nachfolgenden Systemaufrufen auf die Datei zugegriffen werden kann.<br />

Aufruf nach Posix-Standard<br />

ÒØ ÓÔÒ<br />

ÓÒ×Ø Ö ÐÒÑ<br />

ÒØ Ð×<br />

ÑÓØ ÑÓ<br />

Ð× spezifiziert die Zugriffsart, z.B. lesend, schreibend, erzeugend,<br />

anhängend (append); ÑÓ spezifiziert die Zugriffsrechte für neu erzeugte<br />

Dateien. In Windows NT/2000 wird der Systembefehl ÖØÐ zum<br />

Öffnen einer Datei bzw. zum Erzeugen einer neuen Datei verwendet. Analog zu<br />

ÓÔÒ wird als Ergebnis ein Dateideskriptor zurückgegeben (Datentyp Handle).<br />

Die Anzahl der Dateideskriptoren ist beschränkt.<br />

ÐÓ×<br />

Schließen einer Datei; Aufrufparameter ist ein Dateideskriptor. Bei<br />

Terminierung des Prozesses werden alle offenen Dateien automatisch<br />

geschlossen.<br />

185


Schlichter, TU München 6.3. DATEIEN<br />

ÒØ Ö ÒØ Ö ÔÙÖ ÒØ ÑÜ<br />

ÒØ ÛÖØ ÒØ Ö ÔÙÖ ÒØ Ò<br />

ÑÜ gibt die Anzahl der Bytes an, die ohne Pufferüberlauf gelesen werden<br />

können; Ö liefert als Ergebnis die Anzahl der erfolgreich gelesenen Bytes.<br />

Daneben gibt es noch weitere Operationen, z.B. Positionieren des Dateizeigers<br />

auf eine bestimmte Position in der Datei (Ð× oder ËØÐÈÓÒØÖ bei<br />

Win32).<br />

– Dateipuffer<br />

Zugriffe auf Dateien erfolgen über einen Dateideskriptor und einen<br />

Dateipuffer.<br />

Datei<br />

Deskriptor<br />

Dateipuffer<br />

Dateizeiger<br />

Puffer<br />

Pufferposition<br />

Ortsinformation<br />

Externer Speicher Datei<br />

Die für den lesenden und schreibenden Zugriff notwendigen Informationen<br />

werden in einer eigenen Datenstruktur (Dateipuffer) gespeichert, die<br />

jedem geöffneten Dateideskriptor zugeordnet wird. Diese Datenstruktur<br />

enthält neben der Ortsinformation, die Aufschluss über den physischen<br />

Aufenthaltsort der Datei auf einem externen Speichermedien gibt, einen<br />

Puffer zur Zwischenspeicherung von Daten. Der Puffer beinhaltet eine Kopie<br />

eines bestimmten Dateiausschnitts. Die Position dieser Kopie innerhalb der<br />

Datei speichert der Zeiger Pufferposition. Der Dateizeiger spezifiziert die<br />

aktuelle Lese-/Schreibposition.<br />

186


Schlichter, TU München 6.4. MEMORY-MAPPED DATEIEN<br />

6.4 Memory-Mapped Dateien<br />

Eine Datei oder Teile davon werden in den virtuellen Adressraum eines Prozesses<br />

eingeblendet. Das Dateisystem bestimmt einen hinreichend großen Bereich im<br />

virtuellen Adressraum für den Dateiausschnitt, z.B. zwischen Laufzeitkeller und<br />

Halde. Für diesen Teilbereich müssen entsprechende Seitentabellendeskriptoren<br />

initialisiert werden. Nutzung von "Prefetching", um bereits im Voraus<br />

Dateiblöcke in Seiten zu laden.<br />

¯ Lese- und Schreiboperationen, sowohl sequentiell als auch wahlfrei, erfolgen<br />

über virtuelle Adressen.<br />

¯ Einblendung immer nur Vielfacher ganzer Blöcke einer Datei.<br />

¯ veränderte Blöcke werden meist aus Effizienzgründen zu einem späteren<br />

Zeitpunkt zurückgeschrieben. Auf jeden Fall werden die veränderten Blöcke<br />

beim Schließen der Datei auf den externen Speicher zurückgeschrieben.<br />

¯ Beispiel der Win32-Programmierschnittstelle:<br />

ÀÒÐ Ñ<br />

ÖØÐ ÐÒÑ ÒÖ Ö <br />

ÐÒ ØÐËÞ <br />

Ñ ÖØÐÅÔÔÒ ÈÖÓÒÐÝ <br />

Ö ÅÔÎÛÇÐ Ñ ÐÑÔÖ <br />

Der Rückgabewert addr speichert die Anfangsadresse der Datei im virtuellen<br />

Adressraum. In der Regel wählt das Dateisystem den virtuellen Adressbereich<br />

aus.<br />

6.5 Verzeichnisse<br />

Verzeichnisse (engl. directories) erlauben eine hierarchische Strukturierung des<br />

externen Speichers.<br />

¯ baumartige Verzeichnisstruktur mit links zwischen Unterbäumen.<br />

¯ Pfadnamen zur Spezifikation von Dateien und Verzeichnissen. Der vollständige<br />

und eindeutige Namen einer Datei oder eines Verzeichnisses entsteht durch<br />

eine Aneinanderreihung aller Verzeichnisnamen beginnend beim Wurzelverzeichnis;<br />

Unterscheidung zwischen absoluten und relativen Dateinamen.<br />

¯ typische Operationen: create, delete, opendir, closedir, readdir, rename, link,<br />

unlink.<br />

187


Schlichter, TU München 6.6. SCHICHTENMODELL<br />

6.6 Schichtenmodell<br />

Ein Dateisystem kann logisch in 3 Schichten unterteilt werden, die zunehmend<br />

höhere Abstraktionen für die Speicherung persistenter Daten anbieten.<br />

6.6.1 Datenträgerorganisation<br />

Dateiverwaltung<br />

Blockorientiertes Dateisystem<br />

Datenträgerorganisation<br />

Unterteilung des gesamten Datenträgers in Blöcke, die von 0 an aufsteigend<br />

durchnummeriert sind. Das auf MS-DOS aufbauende Dateisystem FAT<br />

(Windows 95) verwendet lediglich maximal 16 Bit für eine Blocknummer.<br />

Bei einer ursprünglichen Blockgröße von 512 Byte können damit externe<br />

Speicher mit bis zu 32 MByte Speicherkapazität angesprochen werden.<br />

Zusammenfassung von Blöcken zu Clustern (32 KByte), um bis zu 2 GByte große<br />

Datenträger zu addressieren; Cluster sind die kleinste Zuteilungseinheit interne<br />

Fragmentierung.<br />

¯ Verwaltung freier und defekter Blöcke.<br />

Defekte<br />

Blöcke<br />

Freie<br />

Blöcke<br />

0<br />

0 0 1 0 0 0 0<br />

Block 0<br />

Block 1 Block 2 Block 3 Block 4 Block 5<br />

0 1 1 0 0 1 0 0<br />

Eine gängige Realisierung der Listen für freie und defekte Blöcke besteht in<br />

zusammenhängenden Bitvektoren, die auf dem Datenträger selbst gespeichert<br />

werden. Diese Realisierung erlaubt den gleichzeitigen Test von 16, 32 oder 64<br />

Bitpositionen mit Hilfe von Logikoperatoren des Prozessors.<br />

188


Schlichter, TU München 6.6. SCHICHTENMODELL<br />

¯ Blockstruktur<br />

Superblock<br />

Freie Blöcke<br />

Defekte<br />

Blöcke<br />

Block 0 Block 1 Block n<br />

Der Superblock verwaltet alle essentiellen Informationen über den Datenträgeraufbau,<br />

z.B. eine Magic Nummer für den Typ des Dateisystems, Anzahl der<br />

Blöcke. Aus Sicherheitsgründen wird der Superblock mehrfach, verteilt über<br />

den gesamten Datenträger, repliziert.<br />

6.6.2 Blockorientiertes Dateisystem<br />

Aufteilung des vorhandenen Speicherplatzes eines logisch durchnummerierten<br />

Datenträgers auf mehrere Dateien.<br />

¯ Dateien besitzen interne Namen.<br />

¯ keine hierarchische Verzeichnisstruktur. Es existieren keine hierarchischen<br />

Verzeichnisstrukturen, d.h. alle Dateien sind in einer flachen Struktur<br />

unmittelbar über den internen Dateinamen ansprechbar.<br />

¯ jede Datei besteht aus einer Menge von Blöcken, die relativ zum Dateianfang<br />

nummeriert sind. Die Blöcke können entweder zusammenhängend oder<br />

verteilt über den Datenträger zugeteilt werden. Im ersten Fall kann dies zu<br />

externer Fragmentierung führen. Die interne Fragementierung hängt von der<br />

Blockgröße ab. Dateien werden immer in Vielfachen von Blöcken belegt.<br />

¯ wesentliche Operationen:<br />

Erzeugen und Löschen von Dateien<br />

Öffnen und Schließen von Dateien<br />

Lesen und Schreiben von Blöcken<br />

6.6.3 Dateiverwaltung<br />

Bereitstellung von Dateien und Verzeichnissen; Dateien werden über Namen<br />

identifiziert. Unix verwendet Dateideskriptoren (sogenannte I-Nodes), die alle<br />

relevanten Dateiattribute einschließlich einer Indexstruktur für die Lokalisierung<br />

der einzelnen Dateiblöcke enthalten. Die Position der ersten 10 Blöcke einer Datei<br />

werden direkt im Deskriptor gespeichert.<br />

189


Schlichter, TU München 6.7. EINBETTUNG DER E/A<br />

I-Node<br />

Schutzbits<br />

Link Count<br />

uid<br />

gid<br />

Größe<br />

Adressen der<br />

ersten 10 Blöcke<br />

einfach indirekt<br />

zweifach indirekt<br />

dreifach indirekt<br />

6.7 Einbettung der E/A<br />

Die Realisierung abstrakter Geräte und die Definition einer generischen<br />

Gerätearchitektur ist charakteristisch für viele Betriebssysteme.<br />

¯ in Unix erfolgt der Zugriff auf praktisch jedes E/A-Gerät über Funktionen des<br />

Dateisystems. Vor dem eigentlichen Zugriff auf ein Gerät muss dieses analog<br />

zu einer Datei geöffnet werden.<br />

¯ in vielen Unix Systemen werden alle Geräte unter dem Teilbaum Ú<br />

verwaltet.<br />

¯ der Dateiname charakterisiert den jeweiligen Typ des E/A-Geräts.<br />

Ú ØØÝ: physische serielle Schnittstelle<br />

Ú ÔØØÝ : abstrakte serielle Schnittstellen<br />

Ú : Diskettenstationen<br />

Ú × : Festplatten<br />

Ú Ð : Netzkarten<br />

190


Kapitel 7<br />

Prozesskommunikation<br />

Disjunkte Prozesse, d.h. Prozesse, die völlig isoliert voneinander ablaufen,<br />

stellen eher die Ausnahme dar. Häufig finden Wechselwirkungen zwischen den<br />

Prozessen statt Prozesse interagieren. Die Unterstützung der Prozessinteraktion<br />

stellt einen unverzichtbaren Dienst dar. Betrachtet man diese Prozesswechselwirkungen<br />

genauer, dann lassen sich 2 grundlegende Interaktionsmuster unterscheiden:<br />

Konkurrenz und Kooperation. Eine Konkurrenzsituation liegt vor,<br />

wenn sich Prozesse gleichzeitig um ein exklusiv benutzbares Betriebsmittel bewerben<br />

Prozesssynchronisation. Bei Prozesskooperation geht es darum, dass<br />

die beteiligten Prozesse gezielt Informationen untereinander austauschen.<br />

7.1 Fragestellungen<br />

Dieser Abschnitt beschäftigt sich mit den Mechanismen von Rechensystemen<br />

zum Austausch von Informationen zwischen Prozessen.<br />

¯ Kommunikationsarten.<br />

¯ nachrichtenbasierte Kommunikation, insbesondere Client-Server-Modell. Die<br />

speicherbasierte Kommunikation, d.h. über gemeinsame Speicherbereiche wird<br />

im Zusammenhang mit Synchronisation (siehe Seite 96) und Semaphoren<br />

behandelt.<br />

¯ Netzwerkprogrammierung auf der Basis von Ports und Sockets.<br />

¯ entfernter Prozeduraufruf.<br />

191


Schlichter, TU München 7.2. EINFÜHRUNG<br />

7.2 Einführung<br />

Prozessinteraktion kann Rechner-lokal und Rechner-übergreifend stattfinden.<br />

Prozesse können auf vielfältige Weise Informationen austauschen.<br />

7.2.1 Kommunikationsarten<br />

implizit<br />

1 : 1<br />

n : 1<br />

1 : m<br />

n : m<br />

Prozesskommunikation<br />

breitbandig schmalbandig<br />

explizit<br />

asnychron<br />

1 : 1<br />

1 : m<br />

n : m<br />

Ströme<br />

explizit<br />

snychron<br />

RPC<br />

RMI<br />

Ereignisse<br />

Alarme<br />

Signale<br />

Die Bandbreite des Kommunikationskanals bestimmt die Datenrate, in der Daten<br />

zwischen Prozessen ausgetauscht werden können. Breit- bzw. schmalbandig<br />

bezieht sich hier auf die Menge der ausgetauschten Information und nicht auf<br />

die Bandbreite des darunterliegenden Kommunikationsnetzes.<br />

Schmalbandige Kanäle<br />

Schmalbandige Kanäle werden im Betriebssystem zum Melden von Ereignissen<br />

oder für die Synchronisation unterstützt. Übertragung von wenigen Bits an<br />

Information, z.B. Setzen von Flags<br />

¯ Dienste des Betriebssystems<br />

Melden von Ereignissen,<br />

Warten auf Ereignisse,<br />

Ereignisverwaltung.<br />

192


Schlichter, TU München 7.2. EINFÜHRUNG<br />

Unterbrechungsereignisse und deren Verwaltung in einem Betriebssystem<br />

wurden bereits eingeführt.<br />

¯ Beim Ablauf von Prozessen können Alarme entstehen (z.B. arithmetische<br />

Alarme). Da das BS keine genauen Kenntnisse über den internen<br />

Berechnungszustand eines Prozesses besitzt, kann man mit den allgemeinen<br />

Standardalarmbehandlungen des BS einen Prozess höchstens abbrechen. Es ist<br />

somit sinnvoll, die Alarmbehandlung dem Prozess selber zu überlassen.<br />

¯ Die Alarme werden über Namen identifiziert, die im BS vereinbart sind. Das<br />

BS stellt Dienste zur Zustellung von Alarmen zur Verfügung. Bemerkung:<br />

schmalbandige Informationskanäle sind für den Bereich der Datensicherheit<br />

problematisch, da sie schwierig zu beherrschen sind. Über diese Kanäle können<br />

sich Angreifer Informationen über das System beschaffen und ausnutzen.<br />

Beispiel: Einloggen unter Solaris 7.0 liefert bereits nach Eingabe der Kennung<br />

Informationen, dass diese Kennung korrekt ist. Lässt sich für einen Passwort-<br />

Cracking-Angriff ausnutzen.<br />

Im folgenden werden wir uns vertiefend mit breitbandigen Kommunikationsformen<br />

beschäftigen, und zwar nicht nur im lokalen Bereich, sondern auch im<br />

verteilten Bereich.<br />

Implizite Kommunikation<br />

Implizite Kommunikation ist eine breitbandige Kommunikationsform. Die<br />

Kommunikation erfolgt über einen gemeinsamen Speicher (Dateien, Register,<br />

Datenstrukturen).<br />

¯ Die Kommunikation findet ohne direkte Unterstützung und ohne Kenntnis des<br />

BS statt.<br />

¯ Vorteil: einfach und schnell (kein Kopieren zwischen Adressräumen).<br />

¯ Nachteil:<br />

a) gemeinsame Bereiche sind nicht immer vorhanden: z.B. in physisch<br />

verteilten, vernetzten Systemen gibt es i.d.R. keinen gemeinsamen<br />

Speicher. Eine Ausnahme bilden sogenannte DSM (Distributed Shared<br />

Memory) Realisierungen.<br />

b) gegebenenfalls aufwendiges busy waiting Mischform: Ereigniszustellung,<br />

d.h. schmalbandige Kommunikation, die das Vorhandensein von Daten<br />

signalisiert.<br />

193


Schlichter, TU München 7.2. EINFÜHRUNG<br />

¯ Implizite Kommunikationsformen<br />

Verschiedene Formen der impliziten Kommunikation<br />

1:1 ein Puffer pro Sender/Empfänger-Paar<br />

n:1 n Sender senden Nachrichten an einen Empfänger, z.B.<br />

Sender: Prozesse senden Druckaufträge<br />

Empfänger: Drucker-Server<br />

1:m Mitteilung an alle Prozesse (Broadcast, Multicast);<br />

Broadcast: z.B. Erfragen, wo ein spezieller Dienst angeboten wird;<br />

Shutdown Message an alle Rechner.<br />

Multicast: z.B. Nachricht an Gruppe gleichartiger Server. Broadcast und<br />

Multicast ist in lokalen Netzen mit busartigen Medien (z.B. Ethernet)<br />

sehr einfach zu realisieren; dort hören alle angeschlossenen Rechner das<br />

Medium ab.<br />

n:m n Erzeuger schreiben in Puffer und m Verbraucher lesen aus Puffer.<br />

n:m Kommunikationsform ist beispielsweise sinnvoll, wenn eine Menge<br />

gleichartiger Dienste zur Verfügung steht, und ein Auftrag von einem<br />

beliebigen dieser Dienstanbieter erledigt werden kann.<br />

194


Schlichter, TU München 7.2. EINFÜHRUNG<br />

S1<br />

prozessspezifischer<br />

oder<br />

zentraler<br />

Puffer<br />

E1<br />

1:1 Kommunikation<br />

Si i-ter Senderprozess<br />

Ei i-ter Empfängerprozess<br />

Explizite Kommunikation<br />

S1<br />

prozessspezifischer<br />

oder<br />

zentraler<br />

Puffer<br />

E1<br />

Sn<br />

n:1 Kommunikation<br />

S1<br />

Briefkasten<br />

(mail box)<br />

Sn<br />

E1 Em<br />

n:m Kommunikation<br />

Diese Kommunikationsart wird realisiert durch den Austausch von Nachrichten<br />

("message passing") nachrichtenbasierte Kommunikation. Die Nachrichtenkommunikation<br />

ist immer dann die geeignete Kommunikationsform, wenn<br />

die beteiligten Prozesse in disjunkten Adressräumen liegen, und damit keine<br />

Möglichkeit haben, auf einen gemeinsamen Speicher zuzugreifen.<br />

¯ Betriebssystem enthält einen Nachrichtendienst ND (das Kommunikationssystem),<br />

der den Austausch der Nachrichten zwischen Prozessen realisiert. ND<br />

unterstützt 2 Systemdienste:<br />

×Ò ÔÖÓ ×× Ñ Ñ××<br />

Ö Ú Ë ÔÖÓ ×× Ñ Ñ××<br />

Mittels ×Ò wird eine Nachricht m für den Empfänger E an den<br />

Nachrichtendienst ND übergeben. Mit Ö Ú entnimmt ein Empfänger E<br />

die Nachricht m, die vom Sender S gesandt wurde, von ND. Der Absender wird<br />

gewöhnlich in der Nachricht m codiert.<br />

¯ prinzipieller Ablauf<br />

195


Schlichter, TU München 7.2. EINFÜHRUNG<br />

Sende<br />

prozess S<br />

Nachricht m<br />

Nachrichten<br />

dienst ND<br />

Nachricht m<br />

Empfänger<br />

prozess E<br />

Falls die Prozesse auf unterschiedlichen Rechnern sind, sind die Nachrichtendienste<br />

der beteiligten Betriebssysteme involviert. In diesem Fall findet eine<br />

Kommunikation zwischen den beiden Nachrichtendiensten statt.<br />

¯ Aufbau einer Nachricht<br />

Eine Nachricht besteht aus 2 grundlegenden Komponenten:<br />

Nachrichtenkopf:<br />

Empfängeridentifikation<br />

Verkehrsinformation, z.B. Sender- und<br />

Nachrichteninhalt: Nutzlast (payload)<br />

¯ explizite Kommunikation ist besonders geeignet in verteilten, vernetzten Systemen.<br />

Die nachfolgenden Abschnitte werden sich mit der nachrichtenbasierten<br />

Kommunikation, insbesondere in verteilten Systemen beschäftigen.<br />

7.2.2 Verteilte Systeme<br />

Bisher haben wir uns mit systemnahen Konzepten von zentralen Systemen<br />

beschäftigt. Seit Ende der 80er Jahre haben jedoch verteilte Systeme rapide an<br />

Bedeutung gewonnen. Die Verteilung bezieht sich sowohl auf die Verteilung<br />

von Hardwarekomponenten (Rechner, Peripherie), als auch auf die Verteilung<br />

von Daten und Verarbeitung. Im letzteren Fall spricht man von einer verteilten<br />

Anwendung, d.h. eine Anwendung besteht aus mehreren kooperierenden<br />

Teilkomponenten, die auf verschiedenen Rechnern ausgeführt werden.<br />

Ansätze zur Kopplung von Recheneinheiten<br />

Vielfach CPU-<br />

Systeme<br />

eng gekoppelt lose gekoppelt<br />

Multiprozessoren Multicomputer verteiltes System<br />

196


Schlichter, TU München 7.2. EINFÜHRUNG<br />

Multiprozessor Multicomputer verteiltes System<br />

Konfiguration nur eigene CPU CPU, Arbeitsspeicher,zschnittstelleNet-<br />

Peripherie gemeinsam gemeinsam,<br />

außer Festplatte<br />

Ort gemeinsames gemeinsamer<br />

Gehäuse Raum<br />

Kommunikation gemeinsamer Ar- direkte<br />

beitsspeicher Verbindung<br />

Betriebssystem ein gemeinsames getrennt, jedoch<br />

BS<br />

gleicher Typ<br />

kompletter Rechner<br />

getrennt<br />

weltweit verteilt<br />

Netzwerk<br />

getrennt, vielfach<br />

unterschiedlich<br />

Verwaltung eine Organisation eine Organisation viele Organisationen<br />

Ein Beispiel für ein eng gekoppeltes Multiprozessor System ist die MI bestehend<br />

aus 4 Rechnerkernen; die Rechnerkerne sind untereinander durch einen Bus<br />

verbunden. Das Rechensystem wird kontrolliert durch ein gemeinsames<br />

Betriebssystem; das Betriebssystem teilt Rechnerkerne und Speicherbereiche<br />

an Prozesse zu; es erfolgt eine parallele Ausführung der Benutzerprogramme;<br />

jeder RK hat den gerade ablaufenden Prozess im gemeinsamen Arbeitsspeicher.<br />

Die Einteilung in Multicomputer oder verteiltes System hängt etwas von der<br />

verwendeten Betrachtungsweise ab.<br />

Charakteristika verteilter Systeme<br />

Netze verbinden autonome Rechner; die Rechner sind oft von verschiedenen<br />

Herstellern mit<br />

inkompatiblen Datendarstellungen,<br />

unterschiedlichen Maschinenbefehlsvorräten, und<br />

verschiedenen Betriebssystemen.<br />

Die verschiedenen Rechner haben keinen gemeinsamen Speicher, d.h. es ist keine<br />

Kommunikation über gemeinsame Variable möglich. Kommunikation zwischen<br />

Prozessen auf verschiedenen Systemen ist nur über Nachrichten möglich (nicht<br />

über gemeinsamen ASP).<br />

¯ mehrfache Existenz von verschiedenen Funktionseinheiten (physische, logische).<br />

Diese können dynamisch verschiedenen Ausführungen zugeteilt werden<br />

und unabhängig voneinander ablaufen; die Funktionseinheiten können hier<br />

Rechnerkerne, ASP, periphere Geräte, aber auch Softwarekomponenten sein;<br />

197


Schlichter, TU München 7.3. NACHRICHTENBASIERTE KOMMUNIKATION<br />

Funktionseinheiten agieren autonom; Funktionseinheiten können hier auch<br />

Teilkomponenten einer verteilten Anwendung sein.<br />

¯ räumliche Verteilung von physischen und logischen Funktionseinheiten.<br />

Die Funktionseinheiten sind mittels eines oder mehrerer Netze miteinander<br />

verbunden; dies ermöglicht Kommunikation zur Synchronisation.<br />

¯ Funktionseinheiten fallen unabhängig voneinander aus.<br />

¯ Transparenz, z.B.<br />

Ortstransparenz. Der Benutzer ist sich des Ortes eines Objektes im<br />

Netz nicht bewusst; Zugriff über einen Namen; Name enthält keine<br />

Ortsinformation.<br />

Zugriffstransparenz. Auf alle, lokale oder entfernte, Objekte werden in ein<br />

und derselben Weise zugegriffen.<br />

Replikationstransparenz. Der Benutzer oder Prozess greift auf replizierte<br />

Objekte (ein Objekt existiert in mehreren Kopien) zu, als seien sie nur<br />

einmal vorhanden, d.h. das Betriebs- bzw. das Ablaufsystem übernimmt<br />

die Aufgabe, die Kopien des Objekts in einem konsistentem Zustand zu<br />

halten. Replikation ist insbesondere für die Verfügbarkeit des Systems und<br />

der Daten von großer Bedeutung.<br />

¯ kooperative Autonomie bei der Interaktion zwischen den physischen bzw.<br />

zwischen den logischen Funktionseinheiten.<br />

7.3 Nachrichtenbasierte Kommunikation<br />

Bei nachrichtenbasierter Prozessinteraktion tauschen Prozesse gezielt Informationen<br />

durch Verschicken und Empfangen von Nachrichten aus; ein Kommunikationssystem<br />

unterstützt an der Schnittstelle wenigstens die Funktionen ×Ò und<br />

Ö Ú. Nachrichtenkommunikation ist die natürliche Form der Prozessinteraktion<br />

in Rechnernetzen. Prozesse, die auf verschiedenen Rechnerknoten platziert<br />

sind, müssen ein physisches Übertragungssystem benutzen, um miteinander in<br />

Kontakt zu treten.<br />

7.3.1 Elementare Kommunikationsmodelle<br />

Klassifikationsschema für die Nachrichtenkommunikation anhand von 2 Dimensionen:<br />

198


Schlichter, TU München 7.3. NACHRICHTENBASIERTE KOMMUNIKATION<br />

generelles Muster der Nachrichtenkommunikation.<br />

zeitliche Kopplung der beteiligten Prozesse.<br />

Klassifikationsschema<br />

¯ Elementare Kommunikationsmuster sind Meldung und Auftrag.<br />

Meldung: Einweg Nachricht vom Sender zum Empfänger (unidirektional).<br />

Die entsprechende Nachrichtentransaktion beginnt mit dem Versenden der<br />

Nachricht und endet mit der Übergabe an den Empfänger. Zu einer<br />

Meldung gehört nicht die anschließende Verarbeitung der Nachricht durch<br />

den Empfänger.<br />

Auftrag: Zweiweg Nachricht zwischen Sender und Empfänger (bidirektional).<br />

Sie beginnt mit dem Versenden eines Auftrags an den Empfänger und<br />

endet mit der Übergabe einer Erfolgsbestätigung über den durchgeführten<br />

Auftrag an den Sender. Dazwischen liegt die Auftragsbearbeitung auf<br />

Empfängerseite, die weitere Nachrichten zur Übertragung der Eingabeparameter<br />

bzw. zur Rückübertragung des Resultates auslösen kann. Im<br />

einfachsten Fall genügen für einen Auftrag 2 Nachrichten: die Auftragsnachricht<br />

und die Resultatnachricht, die gleichzeitig als Quittung dient.<br />

Ausbleibende Quittungen können mittels Timeouts erkannt werden;<br />

sie sind gleichbedeutend mit negativen Quittungen, die auf Senderseite als<br />

nicht durchgeführter Auftrag interpretiert wird.<br />

¯ Synchronität definiert den Kopplungsgrad zwischen Prozessen bei der<br />

Durchführung einer Nachrichtentransaktion:<br />

asynchron: Entkopplung des Senders und Empfängers. Dies bedeutet,<br />

dass ein Sender Nachrichtentransaktionen in schnellerer Folge für einen<br />

Empfänger erzeugen kann, als dieser in der Lage ist, sie zu bearbeiten.<br />

Asynchrone Nachrichtenübertragung erfordert deshalb die Pufferung von<br />

Nachrichten auf dem Übertragungswege zwischen Sender und Empfänger.<br />

Parallelarbeit ist möglich.<br />

synchron: beide Prozesse werden zur Nachrichtenübertragung<br />

synchronisiert.<br />

Es ist auch möglich das Merkmal Synchronität nicht auf die Nachrichtentransaktion,<br />

sondern getrennt auf Sender und Empfänger anzuwenden. Damit<br />

lassen sich asynchrone und synchrone Formen des Nachrichtenversands und<br />

-empfangs beliebig kombinieren.<br />

199


Schlichter, TU München 7.3. NACHRICHTENBASIERTE KOMMUNIKATION<br />

Meldung<br />

¯ Asynchrone Meldung<br />

Sender wird lediglich bis zur Ablieferung der Meldung an das Nachrichtensystem<br />

(Kommunikationssystem) blockiert.<br />

Zeit<br />

send<br />

Sender S Nachrichtendienst ND Empfänger E<br />

Meldung<br />

receive<br />

– Nachrichtendienst des Betriebssystems puffert Nachricht;<br />

Sender S kann seine Ausführung fortsetzen, sobald Nachricht N in den<br />

Nachrichtenpuffer des ND eingetragen ist.<br />

S wartet nicht, bis E die Nachricht empfangen hat.<br />

– Empfänger E zeigt durch receive an, dass er am Empfang der Nachricht N<br />

interessiert ist.<br />

Empfänger wird blockiert, bis Sender Nachricht bereit stellt.<br />

¯ Synchrone Meldung<br />

Sender und Empfänger von Meldungen sind zeitlich gekoppelt.<br />

200


Schlichter, TU München 7.3. NACHRICHTENBASIERTE KOMMUNIKATION<br />

Zeit<br />

send<br />

Sender S Nachrichtendienst ND Empfänger E<br />

Meldung<br />

Quittung<br />

receive<br />

Über die Ablieferung der Nachricht wird der Sender durch eine Quittungsnachricht<br />

informiert, die zur Aufhebung der Blockade des Senders führt.<br />

– Rendezvous-Technik: Sender und Empfänger stellen vor Austausch der<br />

eigentlichen Meldung die Sende- und Empfangsbereitschaft her. In diesem<br />

Fall braucht die Nachricht nirgends gepuffert werden, sondern sie kann direkt<br />

vom Adressraum des Senders in den Adressraum des Empfängers übertragen<br />

werden. Das Erreichen des Rendezvous-Punktes definiert den Zeitpunkt, zu<br />

dem Sender- und Empfängerseite wechselseitiges Einverständnis über das<br />

Vorliegen der Sende- und Empfangsbereitschaft erklärt haben.<br />

Auftrag<br />

¯ Synchroner Auftrag<br />

Bearbeitung der Nachricht durch Empfänger und Senden der Resultatnachricht<br />

sind Teil der Nachrichtentransaktion.<br />

201


Schlichter, TU München 7.3. NACHRICHTENBASIERTE KOMMUNIKATION<br />

Zeit<br />

Sender S Nachrichtendienst ND Empfänger E<br />

send Auftrag<br />

receive<br />

Resultat<br />

Auftrags<br />

bearbeitung<br />

reply<br />

Synchrone Aufträge schränken die Parallelarbeit zwischen Sender und<br />

Empfänger noch stärker ein als synchrone Meldungen, da die zeitliche Kopplung<br />

auch die Bearbeitung der Nachricht umfasst. Diese Kommunikationsform<br />

wird gerade im Zusammenhang mit dem Client-Server Modell sehr oft<br />

verwendet. Das RPC-Konzept ("Remote Procedure Call") ist eine sprachbasierte<br />

Variante der synchronen, auftragsorientierten Kommunikation.<br />

¯ Asynchroner Auftrag<br />

Auftrag und Resultat werden als Paar unabhängiger Meldungen verschickt.<br />

202


Schlichter, TU München 7.3. NACHRICHTENBASIERTE KOMMUNIKATION<br />

Zeit<br />

Sender S Nachrichtendienst ND Empfänger E<br />

send Auftrag<br />

receive<br />

receive<br />

result<br />

Resultat<br />

Auftrags<br />

bearbeitung<br />

reply<br />

Zwischen ×Ò und Ö Ú Ö×ÙÐØ kann der Sender u.U. noch weitere<br />

Aufträge versenden (an den gleichen oder andere Empfänger).<br />

Vorteile/Nachteile asynchrones Senden<br />

¯ Vorteile asynchrones Senden<br />

– nützlich für Realzeitanwendungen. Speziell in Situationen, bei denen<br />

sendender Prozess nicht blockiert werden darf.<br />

– ermöglicht parallele Abarbeitung durch Sender und Empfänger.<br />

– anwendbar zum Signalisieren von Ereignissen.<br />

¯ Nachteile asynchrones Senden<br />

– Verwaltung des Nachrichtenpuffers durch BS erforderlich. Überlauf des<br />

Puffers, Zugriffsprobleme, Absturz von Prozessen.<br />

– Benachrichtigung des Senders S im Fehlerfall und Behandlung von Fehlern<br />

ist problematisch. Warum: Sender hat weitergearbeitet, gegebenenfalls<br />

bereits terminiert; Nachricht kann u.U. nicht mehr wiederholt werden.<br />

– Entwurf und Nachweis der Korrektheit des Systems ist schwierig. Auftreten<br />

von Fehlern abhängig von Pufferinhalten und dem Zeitverhalten des<br />

verteilten Systems (Last des Kommunikationssystems).<br />

203


Schlichter, TU München 7.3. NACHRICHTENBASIERTE KOMMUNIKATION<br />

7.3.2 Erzeuger-Verbraucher Problem<br />

Auf der Basis der nachrichtenbasierten Kommunikation wird das Erzeuger-<br />

Verbraucher Problem mit Hilfe von ×Ò und Ö Ú Operationen realisiert.<br />

ÖÞÙÖ Ë<br />

ÛÐ ØÖÙ ß<br />

ÔÖÓÙÞÖ ØÒÒØ<br />

×Ò ØÒÒØ <br />

<br />

ÎÖÖÙ Ö <br />

ÛÐ ØÖÙ ß<br />

Ö Ú Ë ØÒÒØ <br />

ÚÖÖÙ ØÒÒØ<br />

<br />

Es existiert kein gemeinsamer Speicherbereich, der bzgl. der Zugriffe von<br />

Erzeuger und Verbraucher synchroniert werden muss. Die Synchronisation von<br />

Erzeuger und Verbraucher erfolgt durch das Kommunikationssystem selbst.<br />

7.3.3 Modellierung durch ein Petrinetz<br />

Petri-Netze dienen häufig zur Modellierung von Kommunikationsabläufen,<br />

sogenannten Kommunikationsprotokollen. Sie ermöglichen die Analyse der<br />

Protokolle, z.B. Erkennung von Verklemmungen. Modellierung einer synchronen<br />

Kommunikation:<br />

204


Schlichter, TU München 7.3. NACHRICHTENBASIERTE KOMMUNIKATION<br />

Prozess 1<br />

send<br />

message<br />

wait for<br />

ack.<br />

receive<br />

ack.<br />

Problem: unendliches Warten<br />

Sendebereit<br />

buffer full<br />

buffer full<br />

message<br />

received<br />

ack. received ack. sent<br />

pragmatische Lösung mit Hilfe von Timeouts<br />

receive<br />

message<br />

send<br />

ack.<br />

Prozess 2<br />

¯ Sender bzw. Empfänger warten nur eine festgelegte Zeit, Sender: falls kein<br />

Acknowledgement eintrifft, z.B. erneutes Senden.<br />

¯ Probleme dabei? u.a. Duplikate müssen vom Empfänger erkannt werden;<br />

gesendete Nachrichten kommen zu spät an, sind veraltet etc. Gleiche Probleme<br />

auch in Rechnernetzen: dafür gibt es Protokolle, die die Abläufe genau regeln.<br />

Sequenznummern können als Nachrichtenidentifikatoren dienen.<br />

7.3.4 Ports<br />

Bisher wurde davon ausgegangen, dass ein Prozess eine Nachricht mittels<br />

Ö Ú in seinen Adressraum entgegennehmen kann. Dazu wurde jedem<br />

Prozess ein eigener Nachrichtenpuffer für neu eingetroffene, jedoch noch nicht<br />

abgelieferte Nachrichten zugeordnet. Bisher bestand zwischen Sender und<br />

Empfänger eine feste Beziehung, die über Prozessidentifikatoren (z.B. Namen<br />

oder Nummer) hergestellt wurde. Nachteile<br />

205


Schlichter, TU München 7.3. NACHRICHTENBASIERTE KOMMUNIKATION<br />

Prozessnummern ändern sich mit jedem Neustart.<br />

Prozessnamen sind nicht eindeutig, z.B. falls Programm mehrmals gestartet<br />

wurde.<br />

Deshalb Senden von Nachrichten an Ports. Sie stellen Endpunkte einer<br />

Kommunikation dar. Sie können bei Bedarf dynamisch eingerichtet und gelöscht<br />

werden. Dazu existieren folgende Funktionen:<br />

ÔÓÖØÁ ÖØÈÓÖØ <br />

ÐØÈÓÖØ ÔÓÖØÁ <br />

×Ò ÔÓÖØÁ Ñ×× <br />

Ö Ú ÔÓÖØÁ Ñ×× <br />

Mittels ÖØÈÓÖØ wird ein neuer Kommunikationsendpunkt eingerichtet und<br />

mit dem Adressraum des Prozesses (z.B. Empfänger E) verbunden. Andere<br />

Prozesse, z.B. Sender S, kann nun Nachrichten an den Port des Empfängers<br />

senden. Die Ö Ú Operation benötigt nun den Parameter portID zur<br />

Selektion des Ports. Ports sind eine logische Abstraktion der Adressräume; sie<br />

repräsentieren keine physischen Ports (z.B. serieller oder paralleler Anschluss).<br />

Der Port agiert hier wie eine Warteschlange für den Empfänger E; die<br />

Auslieferung der Nachricht kann willkürlich, festgelegt durch die Reihenfolge<br />

des Eintreffens der Nachrichten, oder festgelegt durch die Nachrichtenprioritäten<br />

erfolgen.<br />

¯ ein Port ist mit dem Adressraum des zugehörigen Prozesses verbunden.<br />

¯ der Empfängerprozess kann sender-spezifische Ports einrichten. Jedem Port<br />

kann ein eigener Thread zugeordnet werden, der die Nachrichten an diesen<br />

Port bearbeitet. Im Ruhezustand ist kein Port eingerichtet, d.h. der Empfänger<br />

kann nur über den fest mit seinem Adressraum assoziierten Nachrichtenpuffer<br />

angesprochen werden.<br />

¯ ein Rechner mit einer IP-Adresse unterstützt mehrere tausend Ports. Für das<br />

TCP-Protokoll sind es 65 535 unterstützte Ports.<br />

¯ der Name des Port ist für einen Rechner eindeutig. Ein Betriebssystem<br />

verwaltet eine bestimmte Anzahl von Ports, die es entweder fest oder<br />

dynamisch verschiedenen Protokollen bzw. deren zugehörigen Applikationen<br />

zuordnen kann.<br />

¯ die Portnummern 1 - 1023 sind fest reserviert für bestimmte Protokolle (bzw.<br />

deren Applikationen).<br />

¯ Übersicht: fest zugeordnete Ports<br />

206


Schlichter, TU München 7.3. NACHRICHTENBASIERTE KOMMUNIKATION<br />

Protokoll Port Beschreibung<br />

FTP 21 Kommandos für Dateitransfer (get, put)<br />

Telnet 23 interaktive Terminal-Sitzung mit entferntem<br />

Rechner<br />

SMTP 25 Senden von Email zwischen Rechnern<br />

time 37 Time-Server liefert aktuelle Zeit<br />

finger 79 liefert Informationen über einen Benutzer<br />

HTTP 80 Protokoll des World Wide Web<br />

POP3 110 Zugang zu Email durch einen sporadisch<br />

verbundenen Client<br />

RMI 1099 Zugang zum Registrieren von entfernten<br />

Java Objekten.<br />

7.3.5 Kanäle<br />

Bisher wurde von einer verbindungslosen Kommunikation ausgegangen, d.h. eine<br />

Nachricht kann an einen Port geschickt werden. Bei einer verbindungsorientierten<br />

Kommunikation muss zuerst eine logische Verbindung zwischen den Kommunikationspartner<br />

eingerichtet werden Kanal ("socket").<br />

¯ Einrichtung eines Kanals zwischen Ports, d.h. Verknüpfen zweier Ports.<br />

¯ bidirektionale Übertragung über Kanäle. Ports sind nicht mehr nur<br />

Empfangsstellen für Nachrichten, sondern sie dienen auch als Quellen. Damit<br />

sind komplexere Auftragsbeziehungen zwischen den Kommunikationspartnern<br />

möglich. Beispielsweise müssen nicht alle benötigten Daten in der<br />

Auftragsnachricht mitgeschickt werden, sondern sie können bei Bedarf vom<br />

beauftragten Prozess angefordert werden.<br />

¯ Die Sende- bzw. Empfangsoperation bezieht sich auf die lokale PortID;<br />

×Ò ÐÓ Ð ÔÓÖØÁ Ñ×× <br />

Ö Ú ÐÓ Ð ÔÓÖØÁ Ñ×× <br />

¯ TCP/IP unterstützt verbindungsorientierte Kommunikation.<br />

7.3.6 Ströme<br />

Ströme (engl. streams) sind eine Abstraktion von Kanälen. Sie verdecken die<br />

tatsächlichen Nachrichtengrenzen. Ein Sender schickt mittels send-Operationen<br />

Nachrichten an den Empfänger. Die Nachrichten werden jedoch logisch zu<br />

einem Bytestrom vereinigt, dem man auf Empfangsseite die Nachrichtengrenzen<br />

207


Schlichter, TU München 7.4. CLIENT-SERVER-MODELL<br />

nicht mehr entnehmen kann. Der Empfänger kann den Bytestrom in Portionen<br />

verarbeiten, ohne sich an den ursprünglichen Nachrichtengrenzen zu orientieren.<br />

Sender<br />

send (120 Bytes)<br />

send (74 Bytes)<br />

send (233 Bytes)<br />

Strom<br />

1 Byte<br />

receive (50 Bytes)<br />

receive (377 Bytes)<br />

Empfänger<br />

Bemerkung: breitbandige, verbindungsorientierte Kommunikation kann auch<br />

für Angriffe in vernetzten Systemen ausgenutzt werden. Ein Beispiel aus der<br />

Vergangenheit: Angriffe auf Yahoo und amazon.com. Aufbau einer Vielzahl Port-<br />

Verbindungen, Übertragung großer Datenmengen (1 GB) führte zum Lahmlegen<br />

des Dienstes ("Denial of Service").<br />

¯ BS-Dienste: Verbindungsauf- und -abbau, schreiben in Strom, lesen aus Strom.<br />

¯ Beispiel: Ströme innerhalb eines Unix-Rechners über Pipe-Konzept: FIFOartiger<br />

Datentransfer mit Operationen: open pipe, read, write.<br />

¯ Dienste für Dateizugriffe oder Zugriffe auf Geräte: spezielle Ausprägung der<br />

stromorientierten Kommunikation.<br />

¯ I/O in Java basiert auf Ströme.<br />

Klasse Ú Ó ÇÙØÔÙØËØÖÑ zum Schreiben von Daten<br />

Klasse Ú Ó ÁÒÔÙØËØÖÑ zum Lesen von Daten<br />

Spezialisierungen z.B. durch FileOutputStream, BufferedOutputStream oder<br />

FileInputStream.<br />

7.4 Client-Server-Modell<br />

Client-Server Modell basiert i.a. auf der Kommunikationsklasse der synchronen<br />

Aufträge. Server stellen Dienste zur Verfügung, die von vorher unbekannten<br />

Clients in Anspruch genommen werden können.<br />

208


Schlichter, TU München 7.4. CLIENT-SERVER-MODELL<br />

Zeit<br />

Client C Server S<br />

blockiert<br />

Auftrag<br />

Resultat<br />

Ausführung<br />

Client ruft Operation eines Servers auf; nach Ausführung der Operation wird<br />

das Ergebnis an Client übergeben. Während der Ausführung der Operation wird<br />

Ablauf des Client meist unterbrochen. Eine leere Antwort ist möglich, falls die<br />

Operation kein Ergebnis liefert (z.B. Eintrag einer Informationseinheit in eine<br />

Datenbank).<br />

¯ Definitionen<br />

– Definition: Client<br />

Ein Client ist eine Anwendung, die auf einer Clientmaschine läuft und i.a.<br />

einen Auftrag initiiert, und die den geforderten Dienst von einem Server<br />

erhält.<br />

Clients sind meist a-priori nicht bekannt. Clients sind oft Benutzerprozesse,<br />

die dynamisch erzeugt und gelöscht werden.<br />

– Definition: Server<br />

Ein Server ist ein Subsystem, das auf einer Servermaschine läuft und einen<br />

bestimmten Dienst für a-priori unbekannte Clients zur Verfügung stellt. Es<br />

existiert eine einfache n:1 Auftragsbeziehung zwischen den Clients und<br />

einem Server.<br />

– Server sind dedizierte Prozesse, die kontinuierlich folgende Schleife<br />

abarbeiten.<br />

ÛÐ ØÖÙ ß<br />

Ö Ú ÑÔÒ×ÔÓÖØ ÙØÖ <br />

Ö ÙØÖ Ù× ÙÒ ÖÞÙ ÒØÛÓÖØÒ Ö Ø<br />

×ØÑÑ ×ÒÔÓÖØ Ö ÒØÛÓÖØÒ Ö Ø<br />

×Ò ×ÒÔÓÖØ Ö×ÙÐØØ <br />

<br />

209


Schlichter, TU München 7.5. NETZWERKPROGRAMMIERUNG<br />

Der Empfangsport ist server-lokal; der Sendeport ist lokal beim Client.<br />

Ein Server kann intern aus einer Menge von Threads aufgebaut sein. Ein<br />

Thread, der sogenannte Listener wartet auf Aufträge. Er verteilt eintreffende<br />

Aufträge an sogenannte Worker-Threads, die die Bearbeitung eines Auftrags<br />

übernehmen. Die Ergebnisse werden direkt vom Worker-Thread an den<br />

Client weitergeleitet.<br />

– Client und Server kommunizieren über Nachrichten, wobei beide Systeme<br />

auf unterschiedlichen Rechnern ablaufen können und über ein Netz<br />

miteinander verbunden sind.<br />

¯ Beispiele für Dienste (Services), die mittels Server realisiert werden:<br />

Dateidienst, Zeitdienst, Namensdienst.<br />

¯ ein System kann sowohl Client als auch Server sein.<br />

– Beispiel<br />

Web<br />

Browser<br />

(Applets)<br />

Client<br />

Server<br />

Client<br />

HTTP<br />

Web<br />

Server<br />

cgi<br />

7.5 Netzwerkprogrammierung<br />

Server<br />

Anwendungs<br />

Server<br />

SQL<br />

Daten<br />

bank<br />

Bedingt durch rasche Verbreitung des Internet hat auch das Interesse an Netz-<br />

Anwendungen sehr zugenommen. Netz-Anwendungen sind verteilte Anwendun-<br />

210


Schlichter, TU München 7.5. NETZWERKPROGRAMMIERUNG<br />

gen, die jeweils aus mehreren Teilkomponenten bestehen und die im Netz verteilt<br />

auf verschiedenen Rechensystemen ausgeführt werden. Teilkomponenten sind<br />

hier nicht einzelne Objekte, sondern komplexe Verarbeitungseinheiten (z.B. ein<br />

Modul bestehend aus einer Menge von Objekten). Eine verteilte Anwendung<br />

ist eine Anwendung A, dessen Funktionalität in eine Menge von kooperierenden<br />

Teilkomponenten A , .., A ,n IN, n 1 zerlegt ist;<br />

1 n<br />

Jede Teilkomponente umfasst Daten (interner Zustand) und Operationen, die<br />

auf den internen Zustand angewendet werden.<br />

Teilkomponenten A i sind autonome Prozesse, die auf verschiedenen<br />

Rechensystemen ausgeführt werden können. Mehrere Teilkomponenten<br />

können demselben Rechensystem zugeordnet werden.<br />

Teilkomponenten A tauschen über das Netz untereinander Informationen aus.<br />

i<br />

Die Teilkomponenten können z.B. auf der Basis des Client-Server Modells realisiert<br />

werden. Beispiele von verteilten Anwendungen sind Softwaresysteme für<br />

verteilte Geldautomaten oder Flugbuchungssysteme. Netzwerkprogrammierung<br />

ist ein Hilfsmittel zur Implementierung verteilter Anwendungen.<br />

7.5.1 Einführung<br />

In Berkeley Unix wurde das Konzept von Sockets eingeführt, um die<br />

Netzwerkprogrammierung zu erleichtern. Sie erlauben jede Netzverbindung<br />

als einen Strom von Bytes zu betrachten, die gelesen bzw. geschrieben<br />

werden können. Ein Socket definiert einen einfachen, bidirektionalen <br />

Kommunikationskanal (siehe Seite 207) zwischen 2 Rechensystemen, mit Hilfe<br />

dessen 2 Prozesse über ein Netz miteinander kommunizieren können.<br />

Input Strom<br />

Client Server<br />

Output Strom<br />

Socket Verbindung<br />

211


Schlichter, TU München 7.5. NETZWERKPROGRAMMIERUNG<br />

Socket Grundlagen<br />

Sockets abstrahieren von den technischen Details eines Netzes, z.B. Übertragungsmedium,<br />

Paketgröße, Paketwiederholung bei Fehlern, Netzadressen. Anfänglich<br />

standen Sockets nur in Unix Umgebungen zur Verfügung. In der Zwischenzeit<br />

werden sie auch von Windows, dem MacOs und von Java unterstützt.<br />

¯ Ein Socket kombiniert 2 Ströme, einen Input- und einen Output-Strom.<br />

¯ Ein Socket unterstützt die folgenden Basisoperationen:<br />

richte Verbindung zu entferntem Rechner ein ("connect").<br />

sende Daten.<br />

empfange Daten.<br />

schließe Verbindung.<br />

assoziiere Socket mit einem Port.<br />

warte auf eintreffende Daten ("listen").<br />

akzeptiere Verbindungswünsche von entfernten Rechnern (bzgl. assoziiertem<br />

Port).<br />

Die ersten 4 Operationen sind sowohl für den Client als auch den Server<br />

relevant (siehe Java's Socket Class), während die letzten 3 Operationen nur<br />

für einen Server von Bedeutung sind (siehe Java ServerSocket Class). Die<br />

Endpunkte einer Socket werden durch Ports repräsentiert.<br />

7.5.2 Server Protokoll<br />

Ein Server kommuniziert mit einer Menge von Clients, die a priori nicht bekannt<br />

sind. Ein Server benötigt eine Komponente (z.B. ein Verteiler-Thread (siehe<br />

Seite 92)), die auf eintreffende Verbindungswünsche reagiert. Diese Komponente<br />

wird auch Listener genannt. Der Hauptunterschied zwischen Client und Server<br />

bzgl. der Socket-Verbindung liegt darin, dass ein Server die Assoziierung mit<br />

einem Port vornimmt und Verbindungswünsche akzeptiert.<br />

¯ Informeller Ablauf aus Serversicht<br />

1. Erzeugen eines SocketServer und Binden an einen bestimmten Port. Ein Port<br />

entspricht einer FIFO Warteschlange. Sie sammelt die Verbindungswünsche<br />

der Clients. Die maximale Länge ist abhängig vom Betriebssystem, z.B. 50.<br />

Falls die Warteschlange voll ist, werden keine weiteren Verbindungswünsche<br />

akzeptiert.<br />

212


Schlichter, TU München 7.5. NETZWERKPROGRAMMIERUNG<br />

2. Warten auf Verbindungswünsche von Clients. Falls der Client bzgl. einer<br />

Socketverbindung autorisiert ist, akzeptiert der Server den Verbindungswunsch.<br />

Der Server wird blockiert, bis die accept-Methode des Servers die<br />

Verbindung zwischen Client und Server eingerichtet hat. Die beiden Ströme<br />

der Socketverbindung werden eingerichtet.<br />

3. Austausch von Daten zwischen Client und Server entsprechend einem<br />

wohldefinierten Protokoll (z.B. HTTP).<br />

4. Schließen einer Verbindung (durch Server, durch Client oder durch beide);<br />

weiter bei Schritt 2.<br />

¯ Programmstück<br />

ËÓ Ø ×Ó Ø ÖÖÒ ØÓ ×Ó Ø<br />

ËÖÚÖËÓ Ø ÔÓÖØ Ø ÔÓÖØ Ø ×ÖÚÖ Ð×ØÒ× ØÓ<br />

ØÖÝ ß<br />

ÔÓÖØ ÒÛ ËÖÚÖËÓ Ø <br />

×Ó Ø ÔÓÖØ ÔØ ÛØ ÓÖ ÐÒØ ÐÐ<br />

ÓÑÑÙÒ Ø ÛØ ÐÒØ<br />

×Ó Ø ÐÓ×<br />

<br />

Ø ÁÇÜ ÔØÓÒ ß ÔÖÒØËØ ÌÖ <br />

¯ Für das Abhören des Ports kann ein eigener Verteiler-Thread spezifiziert<br />

werden; die Bearbeitung übernehmen sogenannte Worker-Threads. Der Unix<br />

FTP Server erzeugt i.a. für jede Verbindung einen eigenen Prozess, was einen<br />

großen Overhead verursacht FTP Server können deshalb oft nicht mehr als<br />

400 offene Verbindungen unterstützen, falls noch vernünftige Antwortzeiten<br />

erwartet werden.<br />

7.5.3 Client Protokoll<br />

Der Client initiiert eine Socket-Verbindung durch Senden eines Verbindungswunsches<br />

an den Port des Servers.<br />

Informeller Ablauf aus Clientsicht<br />

1. Erzeugen einer Socket Verbindung. Dazu muss die Adresse des Servers (z.B.<br />

Internet-Adresse) und der Port, auf dem der Server wartet, angegeben werden.<br />

2. Austausch von Daten zwischen Client und Server über die Duplex-Verbindung<br />

entsprechend einem wohldefinierten Protokoll (z.B. HTTP).<br />

3. Schließen einer Verbindung (durch Server, durch Client oder durch beide).<br />

213


Schlichter, TU München 7.5. NETZWERKPROGRAMMIERUNG<br />

Programmstück<br />

ËÓ Ø ÓÒÒ ØÓÒ ÖÖÒ ØÓ ×Ó Ø<br />

ØÖÝ ß<br />

ÓÒÒ ØÓÒ ÒÛ ËÓ Ø ÛÛÛ Ò ØÙÑ <br />

ÓÑÑÙÒ Ø ÛØ ÐÒØ<br />

ÓÒÒ ØÓÒ ÐÓ×<br />

<br />

Ø ÁÇÜ ÔØÓÒ ß ÔÖÒØËØ ÌÖ <br />

7.5.4 Bidirektionale Stromverbindung<br />

Sockets bestehen aus 2 Strömen für die Duplexverbindung zwischen Client<br />

und Server. Diese beiden Ströme werden automatisch beim Einrichten einer<br />

Socket-Verbindung erzeugt. Durch die Verwendung von Strömen kann dieselbe<br />

Programmiermethode verwendet wie bei I/O, Dateizugriff, etc.<br />

¯ Schreiben auf Socket<br />

ÚÓ ÛÖØÌÓËÓ Ø ËÓ Ø ×Ó ËØÖÒ ×ØÖ ØÖÓÛ×<br />

ÁÇÜ ÔØÓÒ ß<br />

ÓËØÖÑ ×Ó ØÇÙØÔÙØËØÖÑ <br />

ÓÖ ÒØ ×ØÖ ÐÒØ <br />

ÓËØÖÑ ÛÖØ ×ØÖ ÖØ <br />

<br />

¯ Lesen von Socket<br />

ËØÖÒ ÖÖÓÑËÓ Ø ËÓ Ø ×Ó ØÖÓÛ× ÁÇÜ ÔØÓÒ ß<br />

ËØÖÑ ×Ó ØÁÒÔÙØËØÖÑ <br />

ËØÖÒ ×ØÖ <br />

Ö <br />

ÛÐ Ö ËØÖÑ Ö Ò<br />

×ØÖ ×ØÖ <br />

ÖØÙÖÒ ×ØÖ<br />

<br />

Man beachte, dass ein Byte und Char nicht direkt verglichen werden können.<br />

Deshalb muss das Byte in ein Char konvertiert werden. Vom Strom wird jeweils<br />

bis zum nächsten Zeilenende gelesen. Die gelesene Zeile wird als Ergebnis<br />

zurückgegeben.<br />

7.5.5 Java Socket Class<br />

Java unterstützt die beiden grundlegenden Klassen:<br />

214


Schlichter, TU München 7.5. NETZWERKPROGRAMMIERUNG<br />

Ú ÒØ ËÓ Ø zur Realisierung der Client-Seite einer Socket.<br />

Ú ÒØ ËÖÚÖËÓ Ø zur Realisierung der Server-Seite einer Socket.<br />

Client-Seite einer Socket<br />

¯ Constructor<br />

ÔÙÐ ËÓ Ø ËØÖÒ Ó×Ø ÒØ ÔÓÖØ<br />

ØÖÓÛ× ÍÒÒÓÛÒÀÓ×ØÜ ÔØÓÒ ÁÇÜ ÔØÓÒ<br />

Der Parameter host ist ein Rechnername, z.B. www11.in.tum.de. Falls der<br />

Domain Name Server den Parameter host nicht auflösen kann, wird die<br />

Exception ÍÒÒÓÛÒÀÓ×ØÜ ÔØÓÒ ausgelöst. Falls die Socket aus einem<br />

anderen Grund nicht geöffnet werden kann, wird ÁÇÜ ÔØÓÒ ausgelöst, z.B.<br />

der entfernte Host akzeptiert keine Verbindungen. Es gibt noch eine Reihe<br />

anderer Konstruktoren Þ <br />

ÔÙÐ ËÓ Ø ÁÒØÖ×× Ó×Ø ÒØ ÔÓÖØ ØÖÓÛ× ÁÇÜ ÔØÓÒ<br />

Das Objekt der Klasse InetAddress umfasst den Rechnernamen und seine IP-<br />

Adresse, d.h. eine Auflösung durch den Domain Name Server ist nicht mehr<br />

notwendig.<br />

¯ Information über eine Socket<br />

ÔÙÐ ÁÒØÖ×× ØÁÒØÖ×× <br />

liefert als Ergebnis den Namen und IP-Adresse des entfernten Rechners, zu<br />

dem die Socket-Verbindung existiert.<br />

ÔÙÐ ÒØ ØÈÓÖØ <br />

liefert als Ergebnis die Nummer des Ports, mit dem die Socket-Verbindung<br />

am entfernten Rechner assoziiert ist.<br />

ÔÙÐ ÒØ ØÄÓ ÐÈÓÖØ <br />

liefert als Ergebnis die Nummer des Ports, mit dem die Socket-Verbindung<br />

am lokalen Rechner assoziiert ist.<br />

¯ Ein-/Ausgabe<br />

ÔÙÐ ÁÒÔÙØËØÖÑ ØÁÒÔÙØËØÖÑ ØÖÓÛ× ÁÇÜ ÔØÓÒ<br />

liefert den InputStream, von dem Daten gelesen werden können. Er<br />

unterstützt die Methode read zum Lesen der Daten. InputStream ist ein<br />

Basis-Strom, der mit Hilfe von SubClassing spezialisiert werden kann.<br />

ÔÙÐ ÇÙØÔÙØËØÖÑ ØÇÙØÔÙØËØÖÑ ØÖÓÛ× ÁÇÜ ÔØÓÒ<br />

liefert den OutputStream, in dem Daten geschrieben werden können. Er<br />

unterstützt die Methode write zum Schreiben der Daten. OutputStream ist<br />

ein Basis-Strom, der mit Hilfe von SubClassing spezialisiert werden kann.<br />

215


Schlichter, TU München 7.6. REMOTE PROCEDURE CALL<br />

Die beiden Methoden stehen natürlich auch auf Server-Seite einer Socket-<br />

Verbindung zur Verfügung.<br />

Server-Seite einer Socket<br />

¯ Constructor<br />

ÔÙÐ ËÖÚÖËÓ Ø ÒØ ÔÓÖØ<br />

ØÖÓÛ× ÁÇÜ ÔØÓÒ ÒÜ ÔØÓÒ<br />

erzeugt eine Socket auf Server-Seite und assoziiert sie mit dem Port. Falls<br />

die Socket nicht an den angegebenen Port gebunden werden kann, wird<br />

ÒÜ ÔØÓÒ ausgelöst. Es existieren noch weitere Konstruktoren, z.B.<br />

ÔÙÐ ËÖÚÖËÓ Ø ÒØ ÔÓÖØ ÒØ ÕÙÙÄÒØ<br />

ØÖÓÛ× ÁÇÜ ÔØÓÒ ÒÜ ÔØÓÒ<br />

Die Länge der mit dem Port verbundenen Warteschlange wird durch den<br />

Parameter queueLength angegeben.<br />

¯ Einrichten/Schließen einer Verbindung<br />

ÔÙÐ ËÓ Ø ÔØ ØÖÓÛ× ÁÇÜ ÔØÓÒ<br />

diese Methode blockiert und wartet auf Verbindungswünsche von Clients.<br />

ÔÙÐ ÚÓ ÐÓ× ØÖÓÛ× ÁÇÜ ÔØÓÒ<br />

¯ Ein-/Ausgabe<br />

ÔÙÐ ÁÒÔÙØËØÖÑ ØÁÒÔÙØËØÖÑ ØÖÓÛ× ÁÇÜ ÔØÓÒ<br />

liefert den InputStream, von dem Daten gelesen werden können.<br />

ÔÙÐ ÇÙØÔÙØËØÖÑ ØÇÙØÔÙØËØÖÑ ØÖÓÛ× ÁÇÜ ÔØÓÒ<br />

liefert den OutputStream, in dem Daten geschrieben werden können.<br />

7.6 Remote Procedure Call<br />

Realisierung des Client-Server Modells auf der Basis von Auftrags- und<br />

Antwortnachrichten ist komplex und fehleranfällig, da der Programmierer explizit<br />

den Code für den Aufbau und die Interpretation der Nachrichten entwerfen und<br />

implementieren muss.<br />

Meist wird deshalb die Abstraktion des entfernten Prozeduraufrufs,<br />

genannt RPC ("remote procedure call") zur Realisierung des Client-Server<br />

Modells verwendet.<br />

¯ Lokaler Prozeduraufruf<br />

216


Schlichter, TU München 7.6. REMOTE PROCEDURE CALL<br />

Aufruf<br />

Aufrufer Prozedur<br />

Antwort<br />

einzelner Prozess<br />

Eine Prozedur wird traditionell als Mittel zur Strukturierung der Funktionalität<br />

verwendet; die Implementierung einer Prozedur wird nach außen hin<br />

verborgen. Bei Prozeduraufruf werden sowohl Daten als auch Ablaufkontrolle<br />

vom Aufrufer an die Prozedur übergeben. Es findet ein verzahnter Ablauf<br />

von Aufrufer und Prozedur ("single-threaded execution"). Beide, Aufrufer und<br />

Prozedur, werden im gleichen Adressraum ausgeführt. RPC ist die Erweiterung<br />

derselben Art von Kommunikation auf Programme, die auf verschiedenen<br />

Rechnern ablaufen; der verzahnte Ablauf und Transfer von Daten bleiben<br />

erhalten.<br />

¯ RPC ist eine Verallgemeinerung des lokalen Prozeduraufrufs. Ähnlich wie ihn<br />

höhere Programmiersprachen wie Modula, Pascal oder C unterstützen.<br />

¯ Das RPC-Konzept ist die sprachorientierte Variante der synchronen, auftragsorientierten<br />

Kommunikation., d.h. RPC = synchroner Auftrag.<br />

¯ Definition<br />

– Remote Procedure Call (nach Nelson 1982)<br />

"RPC" ist die synchrone Kontrollfluss- und Datenübergabe in Form von<br />

Prozeduraufrufen und von aktuellen Parametern zwischen Programmen in<br />

unterschiedlichen Adressräumen über einen schmalen Kanal (im Sinne von<br />

Durchsatz und Verweilzeit).<br />

217


Schlichter, TU München 7.6. REMOTE PROCEDURE CALL<br />

synchron: der aufrufende Client blockiert solange bis er vom Server<br />

eine Rückmeldung nach Ende der Prozedurbearbeitung erhält; in der<br />

Praxis wird dies nicht so streng durchgeführt, da sonst der Client<br />

möglicherweise unendlich lange warten müsste (Absturz eines Servers)<br />

deshalb Timeout.<br />

Programmiersprache: RPC Aufrufe sind syntaktisch und semantisch in<br />

eine Programmiersprache eingebettet.<br />

unterschiedliche Adressräume: für Client und Server können keine netzweit<br />

eindeutigen Speicheradressen vorausgesetzt werden. Sonderbehandlung<br />

von Pointer erforderlich.<br />

schmaler Kanal: RPC Kommunikation findet über einen speziellen<br />

Interaktionspfad statt (z.B. lokales Netz), der nicht so leistungsfähig ist<br />

wie der lokale, im eigenen Rechner vorhandene Interaktionspfad.<br />

– Ablaufkontrolle<br />

ausführend<br />

wartend<br />

ausführend<br />

Aufruf<br />

Schnittstelle zum<br />

entfernten System<br />

Programm Prozedur<br />

aufrufender<br />

Prozess<br />

Aufruf<br />

Schnittstelle zum<br />

entfernten System<br />

Antwort<br />

Antwort<br />

aufgerufener<br />

Prozess<br />

wartend<br />

ausführend<br />

¯ Lokaler vs. entfernter Prozeduraufruf<br />

Die Attraktivität des RPC-Konzeptes liegt darin, dass mit dem Prozedurkonzept<br />

218


Schlichter, TU München 7.6. REMOTE PROCEDURE CALL<br />

vertraute Programmierer nicht umdenken müssen, wenn sie die Interaktion<br />

zwischen Programmen in disjunkten Adressräumen organisieren. Da es<br />

prinzipiell unerheblich ist, ob die Adressräume auf einem oder mehreren Rechnerknoten<br />

installiert sind, bietet sich der RPC-Mechanismus als elementares<br />

Kommunikationsmittel in verteilten Systemen an. Inzwischen werden RPC-<br />

Systeme als Laufzeitpakete von gängigen Betriebssystemen und Plattformen<br />

für verschiedene Sprachen angeboten.<br />

– Unterschiede zwischen RPC und lokalem Prozeduraufruf<br />

Bei einem RPC haben beide Prozesse (aufrufender und aufgerufener)<br />

£ keinen gemeinsamen Adressraum. Damit ist kein Zugriff auf gemeinsame<br />

globale Daten möglich. Auch ist die Übertragung von Arbeitsspeicheradressen<br />

problematisch, d.h. call-by-reference" ist i.a. nicht realisierbar.<br />

Die aufgerufene Prozedur kann mit Zeigern auf einen fremden Adressraum<br />

wenig anfangen.<br />

£ keine gemeinsame Ausführungsumgebung. Es sind heterogene Ablaufsysteme<br />

oder Rechensystem mit unterschiedlichen Datendarstellungen<br />

möglich.<br />

£ unterschiedliche Lebensdauer. Üblicherweise sind Clients kurzlebig,<br />

während Server eher langlebig sind, d.h. sie werden bei Systemstart<br />

automatisch gestartet.<br />

£ Fehler, bedingt durch Maschinenausfälle oder Kommunikationsfehler.<br />

Bei der <strong>Programmierung</strong> von RPC basierten Anwendungen müssen<br />

Kommunikationsfehler berücksichtigt werden.<br />

– Eigenschaften des RPC-Konzepts<br />

£ einheitliche Aufrufsemantik. Für den Anwendungsprogrammierer gibt<br />

es keinen Unterschied zwischen dem Aufruf einer lokalen und einer<br />

entfernten Prozedur.<br />

£ "type-checking". Die Überprüfung der Datentypen für Parameter und<br />

Ergebnis findet zur Übersetzungszeit statt. Falls die Kommunikation<br />

zwischen Client und Server nur auf der Nachrichtenebene durch den<br />

Programmierer realisiert werden muss, dann erfolgt durch das System<br />

keine Überprüfung der Datentypen.<br />

£ volle Parameterfunktionalität. Der Anwendungsprogrammierer muss aus<br />

Übergabeparameter keine Nachrichtensequenz aufbauen. Jedoch gibt es<br />

gegenüber lokalen Prozeduraufrufen einige wesentliche Unterschiede.<br />

219


Schlichter, TU München 7.6. REMOTE PROCEDURE CALL<br />

Beispielsweise gibt es bei lokalen Prozeduraufrufen die üblichen<br />

Parameterübergaben "call-by-value" und "call-by-reference"; letzters<br />

kann bei RPC nicht so ohne weiteres bereitgestellt werden, da kein<br />

gemeinsamer Adressraum existiert. Eine Möglichkeit besteht in dem<br />

Kopieren der Datenstrukturen zum Server und wieder zurück zum<br />

Client "call-by-copy/restore".<br />

£ Optimierung der Antwortzeit. Beim RPC-Mechanismus ist die Anwortzeit<br />

und nicht der Durchsatz die Größe, die optimiert werden soll.<br />

£ Transparenz. Transparenz für den Programmierer hinsichtlich der<br />

Ausnahmebehandlung von Kommunikationsfehler.<br />

¯ Stubs<br />

Sowohl auf der Client als auch auf der Serverseite werden Stubs verwendet,<br />

um die Besonderheiten von RPC-Aufrufen und die Kommunikation mit dem<br />

Netzwerk Code vom Anwendungsprogramm zu isolieren.<br />

Aufruf<br />

Client C Server S<br />

Antwort<br />

1 8<br />

5 4<br />

Client<br />

7<br />

Kommunikations-<br />

6<br />

Server<br />

Stub<br />

netz<br />

Stub<br />

2 3<br />

Im verteilten Fall sind Client C und Server S nicht zum selben ausführbaren<br />

Code gebunden (anders im lokalen Fall); ein Stub enthält einen Stellvertreter<br />

für jede entfernte Prozedur P; der eigentliche, ausführbare Code von P ist<br />

Teil von S. Stubs übernehmen auch die Konvertierung der Parameter und der<br />

Ergebnisse zwischen internen und externen Darstellungen, d.h. sie rufen die<br />

entsprechenden Datentransformations-Prozeduren ("Filter") auf.<br />

– Client Stub: enthält Stellvertreter Definition von Prozedur P.<br />

– Server Stub: enthält Stellvertreter Aufruf von Prozedur P<br />

– Aufgaben der Stubs<br />

Die Stubs sind gewöhnlich statisch mit dem Hauptprogramm gebunden.<br />

£ Aufgaben Client Stub<br />

Im Client Stub werden die Anforderungsnachrichten ("requests") erzeugt<br />

und an die darunterliegende TCP-Schicht weitergegeben.<br />

220


Schlichter, TU München 7.6. REMOTE PROCEDURE CALL<br />

Æ Spezifikation der aufgerufenen Prozedur.<br />

Æ Zuordnung des Aufrufes zu Zielrechner.<br />

Æ Darstellung der Parameter im Übertragungsformat; Problem: unterschiedliche<br />

Rechner mit unterschiedlichen Datenformaten.<br />

Æ Dekodieren der Ergebnisse und Übergabe an den Client.<br />

Æ Blockierung des Client aufheben.<br />

£ Aufgaben Server Stub<br />

Æ Dekodieren des Aufrufs und der Parameter.<br />

Æ Bestimmung der Aufrufadresse der Prozedur (z.B. mittels einer<br />

Tabelle).<br />

Æ Aufruf der Prozedur. Die eigentliche Bearbeitung des Aufrufs erfolgt<br />

durch Server-Prozeduren.<br />

Æ Kodierung der Ergebnisse. Quittung, Routing und Wiederholung von<br />

Übertragungspaketen wird durch das darunterliegende Transportprotokoll<br />

erledigt.<br />

¯ Wichtige Fragestellungen<br />

Im Zusammenhang mit dem RPC-Konzept gibt es eine Reihe von Fragestellungen,<br />

die behandelt werden müssen.<br />

– Wer ist für das Schreiben der Stubs verantwortlich?Die manuelle Implementierung<br />

von Stubs und deren Schnittstellen zum Netzwerk Code ist oft<br />

aufwendig und fehlerträchtig. Deshalb wird eine automatische Erstellung<br />

der Schnittstelle zwischen Client und Server aus einer deklarativen Beschreibung<br />

angestrebt.<br />

£ Beschreibung der Schnittstelle zwischen Client und Server mit Hilfe<br />

einer deklarative Beschreibungssprache (z.B. Corba IDL); Generierung<br />

der Stubs auf der Basis der Schnittstellenbeschreibung RPC Generator.<br />

£ Erleichtert die Implementierung fehlerfreier Stubs.<br />

– Woher erfährt der Client die Adresse des Servers, an den er den Aufruf<br />

schicken muss?Der Server registriert seine Operation, d.h. er exportiert seine<br />

Schnittstelle. Daraufhin importiert der Client die Serverschnittstelle, d.h. es<br />

erfolgt ein Binden zwischen Client und Server. Der Bindevorgang selbst<br />

kann entweder statisch, semi-statisch oder dynamisch ablaufen.<br />

£ Unterschiedliche Varianten:<br />

Serveradresse fest verdrahtet im Client-Quellprogramm.<br />

Anfrage bei einem Namensdienst. Diese Anfrage kann entweder<br />

am Anfang bei der Client Initialisierung oder vor jedem RPC-Aufruf<br />

erfolgen.<br />

221


Schlichter, TU München 7.6. REMOTE PROCEDURE CALL<br />

– Wie können sich Server gegen unautorisierte Zugriffe abschirmen?Dieser<br />

Aspekt ist insbesondere im Internet, aber auch für Intranets von großer<br />

Bedeutung.<br />

£ Ausweisen über Passwörter oder Zertifikate. Im Hauptstudium werden<br />

die Authentisierungsprotokolle, z.B. Kerberos im Detail besprochen. Ein<br />

weiterer Aspekt ist die Verschlüsselung des Datenaustausches zwischen<br />

Client und Server, um die Information gegenüber Dritte geheimzuhalten.<br />

– Wie geht man Heterogenität um?<br />

£ Unterschiedliche Rechnerarchitekturen verwenden auch unterschiedliche<br />

Datendarstellungen, z.B. für integer Zahlen Stubs müssen Daten in ein<br />

allgemein gültiges Format konvertieren (z.B. XDR).<br />

– Wie geht man mit Kommunikationsfehler bzw. Rechnerabstürzen<br />

um?Rechnerabstürze beziehen sich sowohl auf die Client- als auch auf die<br />

Servermaschine. Beide Rechner können unabhängig voneinander abstürzen.<br />

Kommunikationsfehler werden teilweise durch das TCP Protokoll behandelt,<br />

während Serverabstürze durch den Client bzw. das RPC-Ablaufsystem behandelt<br />

werden müssen.<br />

222


Kapitel 8<br />

Sicherheit in Rechensystemen<br />

In Rechensystemen, die mehreren Benutzern zugänglich sind, ist eine Kontrolle<br />

des Zugriffs auf das Rechensystem selbst, dessen Dienstleistungen und<br />

Datenbestände erforderlich.<br />

8.1 Fragestellungen<br />

Dieser Abschnitt behandelt die Sicherheitsproblematik in zentralen und verteilten<br />

Rechensystemen. Dazu werden verschiedene Schutzmechanismen auf Betriebssystemebene<br />

und für verteilte Systeme vorgestellt.<br />

¯ Zugriffsschutz in Rechensystemen.<br />

¯ Schutzmatrix, insbesondere Zugriffskontrollisten und Capability-Listen.<br />

¯ kurze Einführung in Kryprosysteme.<br />

¯ Authentifizierung in verteilten Systemen.<br />

Die verschiedenen Aspekte der Sicherheit in Rechensystemen werden nur<br />

einführend, und nicht erschöpfend behandelt. Für eine detaillierte Behandlung<br />

der Sicherheitsproblematik sei der Leser auf entsprechende Lehrveranstaltungen<br />

oder die Literatur verwiesen.<br />

8.2 Motivation<br />

Was versteht man unter Sicherheit im Bezug auf Rechensysteme?<br />

223


Schlichter, TU München 8.2. MOTIVATION<br />

Jemand: Unterscheidung von Personen und Gruppen von Personen<br />

davon abhalten: durch technische und organisatorische Maßnahmen<br />

einige: Begrenzung durch unser Vorstellungsvermögen<br />

unerwünschte Dinge zu tun:<br />

1) nicht autorisiert Daten lesen (Geheimhaltung),<br />

2) nicht autorisiert Daten schreiben (Integrität),<br />

3) unter "falscher Flagge" arbeiten (Authentizität),<br />

4) nicht autorisiert Ressourcen verbrauchen (Verfügbarkeit),<br />

usw.<br />

zu tun.<br />

¯ Unterscheidung zwischen Angriffen von<br />

innen. Der Angreifer ist in das Rechensystem bereits eingeloggt und<br />

verschafft sich illegalen Zugriff auf Ressourcen oder Berechtigungen,<br />

z.B. Systemadministrator-Rechte. Mögliche Angriffstechniken sind<br />

Trojanische Pferde, Login-Attrappen, die Nutzung von Hintertüren in<br />

einem Softwaresystem ("trap door") oder die Ausnutzung eines künstlich<br />

herbeigeführten Pufferüberlaufs.<br />

außen. Durch die Vernetzung von Rechnern finden verstärkt auch Angriffe<br />

von entfernten Rechnern über ein Rechnernetz (z.B. das Internet) statt.<br />

Beispiele für mögliche Angriffstechniken sind sogenannte "war-dialer"<br />

(Ausprobieren von Telefonnummern und Passwörtern) oder die Verbreitung<br />

von Viren.<br />

¯ Beispiel: Login-Attrappe<br />

Nutzung von Login-Attrappen in Rechnerumgebungen, wo Rechner von<br />

mehreren Benutzern verwendet werden, um geschützte Benutzerpasswörter zu<br />

erfassen (z.B. in Informatikhalle der Informatik-Fakultät).<br />

– Angreifer startet ein Benutzerprogramm, das am Bildschirm einen Login-<br />

Screen simuliert. Der Angreifer gibt, ohne sich auszuloggen den Rechner<br />

frei. Da am Bildschirm der Login-Screen angezeigt wird, ist ein<br />

nachfolgender Benutzer der Meinung, dass der Rechner verfügbar ist (es sitzt<br />

ja niemand davor und der vorhergehende Benutzer habe durch Ausloggen<br />

seine Sitzung beendet, da der wohlbekannte Login-Screen angezeigt wird).<br />

– Der ahnungslose Benutzer tippt Benutzername und sein privates Passwort.<br />

Angreiferprogramm speichert Benutzername und Passwort in einer<br />

Datei.<br />

224


Schlichter, TU München 8.2. MOTIVATION<br />

Angreiferprogramm terminiert das aktuelle Shell-Programm ("kill"<br />

Systemaufruf) Login-Sitzung des Angreifers wird beendet und<br />

regulärer Login-Screen wird angezeigt.<br />

Der ahnungslose Benutzer nimmt an, dass er sich beim ersten Eintippen<br />

seines Namens oder seines Passwortes vertippt hat und gibt die beiden Daten<br />

erneut ein. Der Angreifer kann auf diese Weise die Passwörter der anderen<br />

Benutzer erfassen.<br />

– Abhilfe: Login-Sequenz wird durch Tastensequenz gestartet, die von einem<br />

Benutzerprogramm nicht erfasst werden kann, z.B. CTRL-ALT-DEL bei<br />

Windows 2000. Falls ein Benutzer diese Tastensequenz eingibt, wird der<br />

aktuelle Benutzer automatisch ausgeloggt und das Login-Programm durch<br />

das Betriebssystem gestartet. Es gibt keinen Weg, um dieses Verhalten des<br />

Betriebssystems zu umgehen.<br />

¯ Beispiel: Pufferüberlauf<br />

Durch einen künstlich herbeigeführten Pufferüberlauf kann ein Angreifer die<br />

Ausführung seines eigenen Programms veranlassen und oft auch noch die<br />

Systemadministrator-Berechtigung (root) erlangen.<br />

– Hintergrund<br />

Die meisten C-Compiler und Laufzeitsysteme überprüfen nicht die Einhaltung<br />

der Feldgrenzen. Da viele aktuelle Betriebssysteme auf der Basis von C<br />

realisiert wurden, ist diese Problematik von großer Bedeutung.<br />

ÒØ <br />

Ö ℄<br />

<br />

℄ <br />

Die Codesequenz ist zwar falsch. Das Laufzeitsystem führt jedoch keine<br />

Überprüfung durch; der Fehler bleibt unentdeckt. In den meisten Fällen<br />

führt dieser Fehler über kurz oder lang jedoch zu einem Programmabsturz<br />

(oft ein Nullpointer). Ein Angreifer kann diese Eigenschaft nutzen, um<br />

Teile des Laufzeitkellers zu überschreiben. Ein Beispiel wäre, das Feld<br />

c für die Speicherung des Pfadnamen einer Datei vorzusehen. Da das<br />

Betriebssystem nur maximal 256 Zeichen pro Pfadenamen unterstützt, ist für<br />

den Programmierer die Länge von c ausreichend. Ein Angreifer kann nun<br />

einen Datei-Pfadnamen angeben, der erheblich länger als 256 ist.<br />

– Veränderung der Rücksprungadresse<br />

225


Schlichter, TU München 8.2. MOTIVATION<br />

Keller<br />

Variable<br />

Hauptprogramm<br />

Programm<br />

Ablauf<br />

Hauptprogramm<br />

SP<br />

SP<br />

Variable<br />

Hauptprogramm<br />

Rückkehradresse<br />

lokale Variable<br />

von A<br />

Feld C<br />

Programm<br />

nach Aufruf der<br />

Prozedur A<br />

C<br />

SP<br />

Variable<br />

Hauptprogramm<br />

Rückkehradresse<br />

lokale Variable<br />

von A<br />

Feld C<br />

Programm<br />

nach Pufferüberlauf<br />

Durch sorgfältiges Analysieren und Berechnen des Speicherlayouts kann<br />

der Angreifer bei Pufferüberlauf die Rückspungadresse der aufgerufenen<br />

Prozedur überschreiben. Der Angreifer überschreibt den Laufzeitkeller<br />

von A einschließlich des Feldes C und der Rücksprungadresse. Die neue<br />

Rücksprungadresse zeigt an den Anfang des Puffers c, an deren Stelle das<br />

vom Angreifer gewünschte ausführbare Programm steht. Der Angreifer<br />

überschreibt als nicht nur die Rücksprungadresse, sondern trägt auch sein<br />

Angriffsprogramm in den Keller des Hostprogramms ein. Beispielsweise<br />

beinhaltet die Zuweisung an das Feld c nicht den Dateinamen, sondern einen<br />

ausführbaren binären Programmcode.<br />

£ Falls das attackierte Programm mit root-Berechtigung (setuid root in<br />

Unix) abläuft, läuft das aufgerufene Programm im Puffer auch mit root-<br />

Berechtigung.<br />

Angreifer kann seiner aufrufenden Shell root-Berechtigung verleihen.<br />

Dadurch erwirbt der Angreifer Superuser Rechte für seine eigenen<br />

Programme und hat damit Zugang auf das gesamte Betriebssystem.<br />

¯ Beispiel: Virus<br />

Ein Virus ist ein Programm, dessen Code an ein anderes Programm anfügt ist<br />

und sich auf diese Weise reproduziert. Zusätzlich kann ein Virus noch andere<br />

Funktionen aufrufen, z.B. Löschen von Dateien, Senden von Nachrichten etc.<br />

Oft ist die Reproduktion des Virus und die Ausführung der Virusfunktion<br />

zeitlich getrennt, d.h. die Virusfunktion wird erst nach Eintreten eines<br />

bestimmten Datums getriggert. Dadurch wird erreicht, dass sich ein Virus<br />

relativ unbemerkt ausbreiten kann (z.B. über das Internet), ohne dass die<br />

226<br />

C


Schlichter, TU München 8.2. MOTIVATION<br />

Benutzer bereits frühzeitig merken, dass ihr Rechner mit dem Virus infiziert<br />

ist.<br />

Virus schläft bis infiziertes Programm ausgeführt wird.<br />

Start des infizierten Programms führt zur Virusreproduktion.<br />

Ausführung der Virusfunktion ist u.U. mit einem zeitlichen Datum<br />

versehen.<br />

mögliche Virustypen sind<br />

– Boot Sector Virus. BIOS liest beim Start des Rechners den Master Boot<br />

Record (MBR) und führt ihn aus. Ein Boot Sector Virus trägt sich im MBR<br />

ein und wird damit bei Rechnerstart jeweils ausgeführt. Der ursprüngliche<br />

MBR Inhalt wird oft auf einen anderen Platz der Festplatte kopiert und<br />

von Virus automatisch aufgerufen, um den Rechnerstart zu ermöglichen.<br />

Nach dem Start speichert sich der Virus oft im Speicherbereich des<br />

Unterbrechungsvektors, um nach jedem Systemaufruf wieder die Kontrolle<br />

zu erhalten.<br />

– Macro Virus. Programme wie Word oder Excel erlauben dem Benutzer<br />

das Schreiben von Macroprogrammen (Visual Basic). Beispielsweise<br />

kann ein Angreifer für ein Word-Dokument ein Macro schreiben, das<br />

mit der ÇÔÒ Ð Funktion verbunden ist. Integriert in das Macro<br />

ist der Virus des Angreifers. Da Macros i.a. alle Systemfunktionen<br />

des Betriebssystems aufrufen dürfen, hat der Virus Zugriff auf die volle<br />

Funktionalität. Die Verbreitung erfolgt durch Versenden des Dokuments,<br />

z.B. als Email Attachment. Öffnen des Dokuments führt zur Ausführung<br />

des Macros und damit des Virus.<br />

– Ausführbares Programm als Virus. Das Virusprogramm sucht nach seinem<br />

Aufruf nach geeigneten ausführbaren Programmen (z.B. "exe Dateien") im<br />

gesamten Dateiverzeichnis und infiziert diese mit dem Virus; beispielsweise<br />

durch Überschreiben des Binärprogramms mit dem Virusprogramm. Die<br />

Länge der Datei wird dadurch verändert (kann genutzt werden durch<br />

Antivirenprogramme, um den Virus zu erkennen).<br />

– Verbreitung von Viren<br />

Früher diente der Austausch von Datenträgern (z.B. Floppy Disk), jetzt das<br />

Internet<br />

als Attachment zu Emails<br />

227


Schlichter, TU München 8.3. SCHUTZMECHANISMEN<br />

Lesen des Adressbuchs und automatische Generierung von Emails<br />

mit Virus Attachment an alle Adressbucheinträge (z.B. von Microsoft<br />

Outlook). Dabei wird oft das Subject-Feld so besetzt, dass der<br />

Empfänger das Gefühl hat, er empfange eine persönliche Email von<br />

einem Bekannten.<br />

8.3 Schutzmechanismen<br />

Schutz von gespeicherter Information vor Diebstahl, unerwünschter Manipulation<br />

und Verletzung der Vertraulichkeit ist ein zentrales Anliegen in allen Mehrbenutzersystemen.<br />

8.3.1 Anforderungen<br />

Für einen Schutzmechanismus gelten die folgenden Anforderungen<br />

¯ alle Objekte eines Systems müssen eindeutig und fälschungssicher identifiziert<br />

werden. Insbesondere muss auch der Aufrufer eines Dienstes eindeutig<br />

und fälschungssicher identifiziert werden. Dies ist gerade für Client-Server<br />

Beziehungen von großer Bedeutung, z.B. die eindeutige Identifizierung des<br />

Client bei Ecommerce Anwendungen.<br />

¯ externer Benutzer eines Systems muss eindeutig und fälschungssicher<br />

identifiziert werden Authentifizierung. Die Zuordnung zu einem<br />

Benutzerprozess muss fälschungssicher sein.<br />

¯ Zugriff auf Objekte sollte nur über zugehörige Objektverwaltung geschehen.<br />

¯ Zugriff auf Objekte nur, wenn Zugreifer die nötige Rechte hat.<br />

¯ Rechte müssen fälschungssicher gespeichert werden; Weitergabe von Rechten<br />

darf nur kontrolliert erfolgen.<br />

¯ Prinzip der minimalen Rechte. Jedem Programm oder Benutzer sollen für<br />

die Objekte nur die Rechte eingeräumt werden, die für die momentane Arbeit<br />

zwingend erforderlich sind.<br />

¯ grundlegenden Schutzmechanismen sollen ohne großen Aufwand überprüft<br />

werden können. Dies bedeutet, dass am besten ein einheitliches Schutzkonzept<br />

für alle zu schützenden Objekte verwendet wird, und dass die Implementierung<br />

zentral in einem möglichst kleinen Baustein, einem Schutzkern im Betriebssystem,<br />

erfolgt.<br />

228


Schlichter, TU München 8.3. SCHUTZMECHANISMEN<br />

8.3.2 Ebenen des Zugriffschutzes<br />

Man unterscheidet die folgenden Ebenen des Zugriffsschutzes.<br />

Maschinenschutz: Kontrolle des physischen Zugangs zum Rechensystem.<br />

Beim direkten Zugang erfolgt die Kontrolle typisch durch organisatorische<br />

und bauliche Maßnahmen. Bei Zugang zu einem Rechner über ein Kommunikationsnetz<br />

sind spezielle Hardware- und Software-Schutzeinrichtungen<br />

vorzusehen, z.B. Benutzer meldet seinen Zugangswunsch an und Rechner ruft<br />

auf einer vorher definierten Nummer zurück (unter der der Benutzer erreichbar<br />

ist).<br />

Zugangskontrolle: Kontrolle des logischen Zugangs zum Rechensystem,<br />

d.h. Ausführung von Aufträgen im Rechensystem. Hier spielt die<br />

Authentifizierung des Benutzers eine wichtige Rolle, z.B. Passwörter oder<br />

biometrische Eigenschaften, um den Benutzer eindeutig zu identifizieren.<br />

Im Rechensystem sind Verfahren notwendig, um die Korrektheit der<br />

angegebenen Identität zu überprüfen (z.B. Passwort-Datei).<br />

Berechtigungskontrolle: Kontrolle des Benutzerzugriffs auf einzelne<br />

Datenbestände und die Ausführung einzelner Dienste.<br />

Systemschutz: Gewährleistung der Integrität der Schutzmechanismen. Hier<br />

muss sichergestellt werden, dass die Schutzmechanismen in Hardware und<br />

Software durch Angreifer nicht modifiziert werden können, um ein Umgehen<br />

und Aushebeln des Schutzes durchzuführen.<br />

8.3.3 Schutzmatrix<br />

Das Konzept der Schutzmatrix wurde von B. Lampson eingeführt. Es verknüpft<br />

Schutzdomänen mit den zu schützenden Objekten.<br />

¯ Schutzdomänen<br />

Definition: Eine Schutzdomäne ist eine Menge von (Objekt, Rechte) Paaren.<br />

Jedes Paar spezifiziert ein Objekt und eine Menge von Operationen, die auf<br />

diesem Objekt ausgeführt werden dürfen. Meist entspricht eine Schutzdomäne<br />

einem Benutzer, d.h. sie gibt an, was dieser Benutzer tun. Negative Rechte,<br />

d.h. das was er nicht tun darf, werden nicht explizit angegeben.<br />

229


Schlichter, TU München 8.3. SCHUTZMECHANISMEN<br />

Domäne 1 Domäne 2<br />

Datei1[R]<br />

Datei2[RW]<br />

Printer1[W]<br />

Datei3[RW]<br />

R = read, W = write, X = execute<br />

Datei1[RWX]<br />

Datei4[R]<br />

Floppy1[R]<br />

Das Beispiel zeigt mehrere Objekte mit Ihren Rechten und ihre Zuordnung<br />

zu den Domänen. Gleiche Objekte (im Beispiel Datei1) können mit<br />

unterschiedlichen Rechten unterschiedlichen Domänen zugeordnet werden.<br />

– Verknüpfung eines Prozesses mit einer Schutzdomäne. Dadurch wird der<br />

Handlungsspielraum des Prozesses bei seiner Ausführung eingeschränkt.<br />

Die Zuordnung einer Schutzdomäne zu jedem Prozess geschieht in einer<br />

allen Zugriffsversuchen vorangeschalteten Authentisierung. Insbesondere<br />

wird die hinter einem Prozess stehende Identität geprüft, z.B. die Identität<br />

des Benutzers oder die eines Servers.<br />

– zu jedem Zeitpunkt wird ein Prozess in einer Schutzdomäne ausgeführt.<br />

Ein Prozess kann während seiner Ausführung die Schutzdomäne wechseln.<br />

Dadurch können Prozesse während ihres Lebenszyklus auf unterschiedliche<br />

Objekte mit unterschiedlichen Rechten zugreifen.<br />

Beispiel Unix: bei Ausführung eines Systemaufrufs wechselt der Prozess<br />

vom Benutzermodus in den Systemmodus ("kernel mode") entspricht<br />

einem Wechsel der Schutzdomäne. Im Systemmodus kann der Prozess<br />

auf die geschützten Ressourcen des Systems zugreifen.<br />

– Das Paar (Prozess P, Schutzdomäne D) wird als Subjekt bezeichnet. Subjekte<br />

sind im Kontext einer Schutzdomäne agierende Prozesse.<br />

Der Zugriffswunsch eines Subjektes S auf ein Objekt o ist definiert als<br />

(D, o, a), wobei D die Schutzdomäne und a die Zugriffsart ist.<br />

– Matrix-Datenstruktur<br />

Konzeptuell verwendet ein Betriebssystem eine Matrix-Datenstruktur, um<br />

die Zuordnung Objekt-Schutzdomäne zu verfolgen.<br />

230


Schlichter, TU München 8.3. SCHUTZMECHANISMEN<br />

Domäne<br />

1<br />

2<br />

Datei1<br />

read<br />

read write<br />

execute<br />

Datei2<br />

read write<br />

Datei3<br />

read write<br />

read write<br />

Objekt<br />

Datei4<br />

read<br />

Printer1<br />

write<br />

write<br />

Floppy1<br />

read<br />

Jedes Matrixelement spezifiziert die Zugriffsarten, die in einer Schutzdomäne<br />

auf das zugehörige Objekt erlaubt sind. Der Domänenwechsel selbst<br />

kann mit Hilfe des Matrixmodells realisiert werden. Zum Beispiel können als<br />

Objekte zusätzlich die Schutzdomänen mit aufgenommen werden. Falls ein<br />

Wechsel von einer Domäne 1 in eine Domäne 2 erlaubt sein soll, wird in die<br />

Zeile der Domäne 1 in der Spalte für Objekt Domäne 2 die Zugriffsart "enter"<br />

eingetragen.<br />

¯ Schutzmonitor<br />

Jeder Zugriff (D, o, a) eines Subjektes S wird mit Hilfe eines Schutzmonitors<br />

überprüft. Der Schutzmonitor prüft anhand seiner intern gespeicherten<br />

Schutzmatrix, ob in der Zeile von D ein Zugriffsrecht a für das Objekt o existiert.<br />

Bei positivem Ausgang wird der Zugriff zugelassen, andernfalls wird<br />

ein Schutzalarm ausgelöst und der Zugriff unterdrückt. Der Schutzmonitor läuft<br />

meist in einem geschützten Teil des Betriebssystems ab (z.B. Betriebssystemkern).<br />

Schutzdomäne<br />

D<br />

Prozess<br />

P<br />

Subjekt<br />

Benutzermodus<br />

(D,o1,a)<br />

Schutzmonitor<br />

Schutz<br />

matrix<br />

Betriebssystem - Systemmodus<br />

Objekte<br />

– der Schutzmonitor ist vertrauenswürdig.<br />

– Subjekte können in keinem Fall auf Objekte unter Umgehung des<br />

Schutzmonitors zugreifen.<br />

– neue Prozesse müssen sich gegenüber dem Schutzmonitor authentifizieren.<br />

Anonyme Prozesse, die noch ohne Schutzdomäne sind, übergeben dem<br />

231<br />

o1<br />

o2<br />

o3


Schlichter, TU München 8.3. SCHUTZMECHANISMEN<br />

Schutzmonitor Namen und Passwort des Benutzers, in dessen Auftrag sie<br />

handeln. Erkennt der Schutzmonitor die Identität an, veranlasst er den<br />

Betriebssystemkern einen Verweis auf die zugeordnete Schutzdomäne im<br />

Prozesskontrollblock zu speichern; der Prozess kann nun auf die erlaubten<br />

Objekten zugreifen.<br />

¯ Schutzmatrix ist typischerweise sehr groß und dünn besetzt eine direkte<br />

Implementierung ist deshalb nicht sinnvoll. Deshalb ist man dazu übergegangen<br />

die Schutzmatrix entweder spaltenweise oder zeilenweise zu speichern, um<br />

den Speicheraufwand zu reduzieren. Leere Matrixelemente werden nicht<br />

gespeichert.<br />

¯ Zugriffskontrollliste<br />

Zugriffskontrolllisten ("Access Control List", ACL) realisieren die spaltenweise<br />

Speicherung der Schutzmatrix.<br />

jedes Objekt o besitzt seine Zugriffskontrollliste.<br />

Element einer Zugriffskontrollliste (ACL-Element) besteht aus Paar<br />

(Prozess, Zugriffsarten). Anstelle des Prozesses können als Komponenten<br />

in einem ACL-Element auch Schutzdomänen verwendet werden. Die<br />

Verwendung von Schutzdomänen erleichtert die Zusammenfassung von<br />

Benutzern zu einer Gruppe, die die gleichen Zugriffsrechte besitzen. Jedes<br />

ACL-Element repräsentiert ein Kontrollrecht für das Objekt o.<br />

Prozess Benutzer<br />

A<br />

Datei D1 A: RW; B: R<br />

Datei D2 A: R; B: RW; C: R<br />

Datei D3 B: RWX; C: RX<br />

B C<br />

ACL<br />

Benutzer<br />

Modus<br />

System<br />

Modus<br />

Neben den allgemeinen Rechten wie Ö, ÛÖØ und Ü ÙØ können auch<br />

objekt-spezifische Zugriffsarten in die Zugriffskontrollliste des Objektes eingetragen<br />

werden. Für einen Prozess (Subjekt) sind nur diejenigen Zugriffsarten<br />

auf das Objekt erlaubt, die in der zugehörigen ACL eingetragen sind. Manche<br />

Schutzsysteme unterstützen auch Wildcards für die Prozessspezifikation, d.h.<br />

ein ACL-Element (*, R) bedeutet, dass beliebige Prozesse das Leserecht auf<br />

das Objekt besitzen.<br />

232


Schlichter, TU München 8.3. SCHUTZMECHANISMEN<br />

¯ Capability-Liste<br />

Capability-Listen ("Zugriffsausweislisten") realisieren die zeilenweise Speicherung<br />

der Schutzmatrix.<br />

jeder Prozess besitzt eine Menge von Capabilities, die die erlaubten<br />

Zugriffe auf Objekte repräsentieren.<br />

Element einer Capability-Liste besteht aus Paar (Objekt, Zugriffsarten). Ein<br />

Capability gibt dessen Besitzer gewisse Zugriffsrechte für das Objekt.<br />

Prozess Benutzer<br />

A<br />

D1: RW<br />

D2: R<br />

D1: R<br />

D2: RW<br />

D3: RWX<br />

B C<br />

D2: R<br />

D3: RX<br />

Benutzer<br />

Modus<br />

System<br />

Modus<br />

Capability-<br />

Liste<br />

– Capabilities müssen geschützt werden, um Modifikationen durch den Prozess<br />

selbst zu verhindern. Alternativen sind<br />

Speicherung im geschützten Bereich des Betriebssystems.<br />

Capabilities sind zwar im Benutzermodus dem Prozess zugeordnet; sie<br />

sind jedoch verschlüsselt. Der Prozess kann bei einem Objektzugriff<br />

dem Schutzmonitor sein zugehöriges Capability vorzeigen, jedoch dieses<br />

Capability nicht selbst verändern. Eine Änderung darf nur vom<br />

Schutzmonitor vorgenommen werden. Diese Alternative ist besonders<br />

für verteilte Systeme geeignet. Beispielsweise schickt ein Client<br />

zusammen mit seiner Dienstanforderung auch das zugehörige Capability<br />

an den Server. Das Capability muss sicher übertragen werden (z.B.<br />

verschlüsselt), damit ein heimliches Kopieren und missbräuchliche<br />

Nutzung durch andere Prozesse verhindert werden kann.<br />

– Capabilities können zeitlich begrenzt werden. Auch könnte mit einem<br />

Capability ein Kontofeld verbunden sein. Bei jeder Verwendung des<br />

Capability wird das Kontofeld reduziert. Ein Objektzugriff ist nur möglich,<br />

wenn der Kontostand ausreichend ist. Damit kann ein Capability nur für eine<br />

begrenzte Anzahl von Zugriffen beschränkt werden.<br />

233


Schlichter, TU München 8.4. SICHERHEIT IN VERTEILTEN SYSTEMEN<br />

¯ Zusammenfassung: Zugriffskontrolllisten und Capability-Listen haben in<br />

gewisser Weise komplementäre Eigenschaften<br />

ACLs erlauben das selektive Zurücknehmen von Rechten. Für Capabilities<br />

ist dies eher schwierig, da die Capabilities verteilt den einzelnen Prozessen<br />

zugeordnet sind, und auch zwischen Prozessen weitergegeben werden<br />

können.<br />

Capabilities können weitergegeben werden. Bei der Weitergabe kann der<br />

Prozess die Zugriffsrechte einschränken.<br />

8.4 Sicherheit in verteilten Systemen<br />

In einem zentralen System beruht der Zugriffsschutz letztendlich auf der Kontrolle<br />

aller Systemkomponenten (Hard-/Software) durch ein einziges, vertrauenswürdiges<br />

Betriebssystem. Die Kontrolle kann aufgrund der Gestaltung der Schnittstelle<br />

durch Benutzer nicht umgangen werden. In einem verteilten System gibt es keine<br />

zentrale Stelle, die alle Subjekte und Objekte kontrollieren kann. Jeder Rechner<br />

hat sein eigenes Betriebssystem, das in Verantwortung des jeweiligen Rechner-<br />

Administrators liegt. Dieser kann die Schutzmechanismen durchbrechen und so<br />

unberechtigten Zugriff zu bestimmten Daten und Ressourcen des Rechnernetzes<br />

erhalten will. Andere Rechner in einem Rechnernetz werden als nicht vertrauenswürdig<br />

eingeschätzt.<br />

8.4.1 Unsicherheitsfaktoren in verteilten Systemen<br />

Durch das Kommunikationsnetz ergeben sich zusätzliche Unsicherheitsfaktoren<br />

in verteilten Systemen.<br />

¯ Anzapfen von Kommunikationspfaden. Diese Gefahr wird insbesondere durch<br />

die offenen Netze erleichtert.<br />

¯ Abhören und Verfälschen von Nachrichten. Dazu gehört Kopieren, Verändern<br />

und Löschen von ganzen bzw. Teilen von Nachrichten sowie das Einfügen von<br />

falschen Teilen in eine Nachricht.<br />

¯ Wiederholen von abgehörten und kopierten Nachrichten ("Replay").<br />

¯ Verändern der Nachrichtenreihenfolge.<br />

¯ Modifizieren der Quell- oder der Zieladresse einer Nachricht.<br />

234


Schlichter, TU München 8.4. SICHERHEIT IN VERTEILTEN SYSTEMEN<br />

¯ Rechnername und Netzadressen allein sind nicht vertrauenswürdig. Falls<br />

ein Benutzer komplette Kontrolle über einen Rechner hat, kann er diesen so<br />

modifizieren, dass er sich für einen anderen Rechner ausgibt. Jemand gibt vor<br />

ein bestimmter Client zu sein, oder jemand gibt vor ein bestimmter Server zu<br />

sein. Es ist also die Authentifizierung von Client und Server notwendig.<br />

¯ Einschleusen von Viren.<br />

¯ Lahmlegen von Servern durch eine massive Anzahl von Anforderungen (siehe<br />

Yahoo, Microsoft). Diese "denial-of-service" Attacken können durch die<br />

automatische Generierung von Anforderungen erreicht werden.<br />

8.4.2 Sicherheitsanforderungen<br />

Für den Empfänger einer Nachricht ist nicht nur die Authentizität des Senders<br />

der Nachricht von Bedeutung, sondern auch die Integrität dieser Nachricht<br />

bzw. der Nachrichtenreihenfolge, d.h. auch eine spätere Wiederholung einer<br />

Nachricht kann die Integrität verletzen. Unterscheidung von wesentlichen<br />

Sicherheitsanforderungen:<br />

¯ Authentizität<br />

Nachweis über den Ursprung der Nachricht, Identität des Senders; Authentizität<br />

von Daten muss garantiert sein, d.h. angebliche Quelle von Daten muss<br />

tatsächlicher Quelle entsprechen. Beispiel im Web: stammen bestimmte<br />

Informationen tatsächlich vom gewünschten Anbieter oder hat jemand<br />

gefälschte Daten untergeschoben? Entsprechendes gilt auch für den Ursprung<br />

einer Email.<br />

¯ Vertraulichkeit, Geheimhaltung<br />

vertrauliche Daten auch bei einer Übertragung über ein öffentliches Netz. Es<br />

soll Dritten nicht möglich sein, die Daten auszuspähen. Gegebenenfalls ist<br />

es sogar notwendig, die Tatsache des Kommunikationsaustausches zwischen 2<br />

Partnern zu verschleiern. Die Tatsache der Kommunikation zwischen 2 Firmen<br />

kann bereits eine interessante Information für Mitbewerber sein.<br />

¯ Verbindlichkeit<br />

Beispielsweise muss der Verkäufer dem Käufer nachweisen können, dass dieser<br />

einen verbindlichen Auftrag über das Netz getätigt hat. Verbindlichkeit ist<br />

insbesondere beim elektronischen Handel von Bedeutung.<br />

235


Schlichter, TU München 8.4. SICHERHEIT IN VERTEILTEN SYSTEMEN<br />

¯ Integrität<br />

Daten müssen vor nicht autorisiertem Schreiben geschützt werden; Schreiben<br />

bedeutet: einfügen, modifizieren, löschen, etc. Falls die übertragenen Daten bei<br />

der Übertragung manipuliert wurden, sollte dies für den Empfänger aufgrund<br />

der verletzten Integrität der Daten bemerkbar sein.<br />

¯ Verfügbarkeit<br />

Schutz von Systemressourcen vor nicht autorisiertem Zugriff, um Verfügbarkeit<br />

für autorisierte Benutzer garantieren zu können.<br />

Systemressourcen: Prozessoren, Speicher, Kommunikationskanäle, Programme,<br />

etc.<br />

8.4.3 Kryptographie<br />

Die Schutzkonzepte in verteilten Systemen basieren auf der Anwendung von<br />

Verschlüsselungstechniken.<br />

Kryptosystem<br />

Definition: Ein kryptographisches System (Kryptosystem) ist ein Tupel (M, C,<br />

K, E ,D ) mit<br />

k k<br />

einem höchstens abzählbaren Klartextraum M<br />

einem höchstens abzählbaren Chiffretextraum C<br />

einem höchstens abzählbaren Schlüsselraum K<br />

einer Familie von Chiffriertransformationen E : M C mit k aus K<br />

k<br />

(Verschlüsselung)<br />

einer Familie von Dechiffriertransformationen D : C M mit k aus K<br />

k<br />

(Entschlüsselung).<br />

A<br />

Klartext Ciphertext<br />

x<br />

E k<br />

y = E k (x)<br />

D k<br />

Klartext<br />

¯ Es muss gelten<br />

k K, m M:D (E (m)) = m<br />

k k<br />

k ist der Schlüssel, wobei beim public-key Verfahren die Schlüssel zum<br />

Chiffrieren und Dechiffrieren unterschiedlich sind. Zusätzlich gibt es noch<br />

236<br />

x<br />

B


Schlichter, TU München 8.4. SICHERHEIT IN VERTEILTEN SYSTEMEN<br />

Forderungen, wie beispielsweise: es müssen einfach und leicht Schlüssel<br />

aus K gefunden werden können; die Chiffrier-und Dechiffriertransformationen<br />

müssen effizient berechenbar sein. Die Sicherheit des Systems beruht auf der<br />

Geheimhaltung von Schlüssel und nicht des Chiffrier- und Dechiffrieralgorithmus.<br />

¯ Unterscheidung zwischen zwei Klassen von Kryptosystemen:<br />

symmetrische Kryptosysteme (private-key)<br />

asymmetrische Kryptosysteme (public-key)<br />

Bei dem symmetrischen Verfahren haben Sender und Empfänger einen privaten<br />

Schlüssel, während beim asymmetrischen Verfahren eine Unterscheidung<br />

gemacht wird zwischen einem öffentlichen Schlüssel zum Verschlüsseln und<br />

einem privaten Schlüssel zum Entschlüsseln.<br />

Symmetrische Kryptosysteme (private-key)<br />

Absender A<br />

Dokument<br />

(Klartext)<br />

Dokument<br />

(chiffriert)<br />

chiffrieren<br />

mit k priv<br />

Netz<br />

Empfänger E<br />

Dokument<br />

(Klartext)<br />

dechiffrieren<br />

mit k priv<br />

Dokument<br />

(chiffriert)<br />

k priv ist ein privater Schlüssel für die Kommunikation zwischen den beteiligten<br />

Prozessen A und E.<br />

¯ Beispiel: DES (Data Encryption Standard)<br />

DES wurde von IBM entwickelt und 1977 von der amerikanischen Regierung<br />

als offizieller Standard propagiert. DES ging ursprünglich von einer festen<br />

Schlüssellänge von 56 Bit plus 8 Bit Parität aus; in der Zwischenzeit sind<br />

Schlüssel 112 Bit und länger. Verfahren gilt als sicher in dem Sinn, dass<br />

es nur mit sehr großem Aufwand möglich ist, einen Schlüssel zu knacken.<br />

Eine Verdoppelung der Schlüssellänge erhöht den zum Knacken notwendigen<br />

237


Schlichter, TU München 8.4. SICHERHEIT IN VERTEILTEN SYSTEMEN<br />

Aufwand um den Faktor 2 56 . Derzeit spezifiziert eine Standardisierungsgruppe<br />

einen Nachfolger von DES.<br />

¯ Schlüsselverteilung<br />

Problem: Sichere Verteilung der geheimen Schlüssel, d.h. sicherer Austausch<br />

der geheimen Schlüssel zwischen Absender A und Empfänger E. Dazu<br />

wird oft ein anderes Kommunikationsmedium gewählt, z.B. ein persönliches<br />

Treffen, d.h. gesicherter Datenaustausch erfordert gewisse Vorbereitungen, eine<br />

spontane gesicherte Übertragung ist nicht möglich.<br />

– Schlüsselverteilungsserver<br />

Ein Schlüsselverteilungsserver (KDS = key distribution server) generiert für<br />

die beiden Kommunikationspartner A und E einen gemeinsamen privaten<br />

Schlüssel und verteilt ihn chiffriert an A und E.<br />

Kommunikations-<br />

KDS<br />

wunsch A und E<br />

1 2<br />

Ek (k S )<br />

A<br />

3<br />

A<br />

M<br />

KS KS 4 5 6<br />

Verschlüsselungs<br />

einheit<br />

E k (M)<br />

S<br />

E k (k S )<br />

E<br />

Verschlüsselungs<br />

einheit<br />

£ Benutzer A und E haben jeweils mit KDS einen gemeinsamen geheimen<br />

Schlüssel (k A und k E für A bzw. E). Diese geheimen Schlüssel werden<br />

bereits a-priori festgelegt, z.B. durch Passwort.<br />

£ KDS generiert auf Anfragen einen Schlüssel für eine Sitzung. Dieser<br />

Schlüssel dient für die Kommunikation zwischen A und E. Er wird<br />

typischerweise nur für eine Sitzung verwendet. Für verschiedene<br />

Kommunikationssitzungen zwischen A und E werden unterschiedliche<br />

Schlüssel verwendet.<br />

£ KDS verteilt Sitzungsschlüssel chiffriert an Partner (Schritte 2 und 3).<br />

£ Partner kommunizieren über gemeinsamen Schlüssel (Schritt 5).<br />

Asymmetrische Kryptosysteme (public-key)<br />

Realisierung eines gesicherten Datenaustausches mittels eines Schlüsselpaares<br />

(k priv ,k pub )<br />

238<br />

M<br />

B


Schlichter, TU München 8.4. SICHERHEIT IN VERTEILTEN SYSTEMEN<br />

k priv ist der private Schlüssel, k pub ist der öffentliche Schlüssel<br />

was mit einem Schlüssel chiffriert wurde, kann mit dem jeweils anderen<br />

Schlüssel wieder dechiffriert werden.<br />

Vorteil des asymmetrischen Verfahrens ist, dass der öffentliche Schlüssel<br />

allgemein bekannt ist, während nur ein Partner (Empfänger oder Sender)<br />

den privaten Schlüssel kennen muss, d.h. es ist keine Vorbereitung durch<br />

Austausch von geheimen Schlüsseln notwendig. Das Verschlüsselungs- und<br />

Entschlüsselungsverfahren ist bekannt.<br />

Absender A<br />

Dokument<br />

(Klartext)<br />

Dokument<br />

(chiffriert)<br />

chiffrieren<br />

mit k E, pub<br />

Netz<br />

Empfänger E<br />

Dokument<br />

(Klartext)<br />

dechiffrieren<br />

mit k E, priv<br />

Dokument<br />

(chiffriert)<br />

¯ Beispiel: RSA-Verfahren<br />

RSA Verfahren mit Schlüssellänge 200 bits; Verschlüsselung langsam;<br />

deshalb oft Kombination mit symmetrischen Verfahren.<br />

¯ Bestimmung der Schlüssel<br />

Bedingt durch die Fortschritte in der Hardware, sollte das Schlüsselpaar alle<br />

zwei Jahre gewechselt werden und auch die Schlüssellänge vergrößert werden.<br />

– Bestimmung des öffentlichen Schlüssels k pub<br />

1. selektiere 2 positive (p = 7, q =17)<br />

2.<br />

Primzahlen p und q;<br />

x = (p-1) * (q-1); (x = 96)<br />

3. bestimme eine Zahl e<br />

mit e kein Teiler von x;<br />

(e = 5)<br />

4. n=p*q; (n = 119)<br />

5. k = (n, e);<br />

pub<br />

(k = (119, 5))<br />

pub<br />

– Bestimmung des privaten Schlüssels k priv<br />

239


Schlichter, TU München 8.4. SICHERHEIT IN VERTEILTEN SYSTEMEN<br />

6. bestimme d, so dass<br />

mod(d*e, x) = 1;<br />

(d * 5/96 = 1 d = 77)<br />

7. k = (n, d)<br />

priv<br />

(k = (119, 77))<br />

priv<br />

– Berechnung des Chiffretext c aus Klartext m (m = 19), d.h. Klartext wird als<br />

eine Zahl interpretiert; Anwendung des Schlüssels k pub<br />

8. c = mod (m e ,n) (c = mod(19 5 , 119) =<br />

66)<br />

– Berechnung des Klartext m aus Chiffretext c; Anwendung des Schlüssels<br />

k<br />

priv<br />

9. m = mod (c d ,n) (p = mod(66 77 , 119) =<br />

19)<br />

¯ Digitale Unterschrift<br />

Absender A<br />

Dokument<br />

(Klartext)<br />

chiffrieren<br />

mit k E, pub<br />

Dokument<br />

(chiffriert)<br />

hash<br />

Signature<br />

chiffrieren<br />

mit k A, priv<br />

Signature<br />

(chiffriert)<br />

Netz<br />

Dokument<br />

(Klartext)<br />

dechiffrieren<br />

mit k E, priv<br />

Empfänger E<br />

Dokument<br />

(chiffriert)<br />

gleich ?<br />

hash<br />

Signature<br />

dechiffrieren<br />

mit k A, pub<br />

Signature<br />

(chiffriert)<br />

Die Unterschrift ("signature") besteht u.a. aus einem Hashcode zum Dokument<br />

sowie Information über den Absender.<br />

8.4.4 Authentifizierungsdienst Kerberos<br />

Kerberos wurde am MIT als Teil des verteilten Systems Athena entwickelt.<br />

Das Authentifizierungsprotokoll von Kerberos basiert auf dem Protokoll<br />

von Needham und Schröder; siehe auch Kerberos Web-Site (URL:<br />

http://web.mit.edu/kerberos/www/)<br />

240


Schlichter, TU München 8.4. SICHERHEIT IN VERTEILTEN SYSTEMEN<br />

Motivation<br />

Kerberos geht von folgenden Komponenten aus<br />

Client C<br />

Server S<br />

Schlüsselverwaltungszentrum KDC ("key distribution center")<br />

Ticket Server TGS ("ticket granting service")<br />

Zielsetzung von Kerberos<br />

¯ ein Client C möchte einen Dienst des Servers S in Anspruch nehmen, dabei<br />

soll mit Hilfe von KDC und TGS die Geheimhaltungs- und Authentizitätsanforderung<br />

erfüllt werden. Der Server S muss überzeugt davon sein, dass er mit<br />

Client C kommuniziert; umgekehrt muss dasselbe aus der Clientperspektive<br />

gelten.<br />

¯ KDC verwaltet die geheimen Schlüssel der registrierten Komponenten. KDC<br />

muss sehr sicher sein und darf auch räumlich für Eindringlinge nicht zugänglich<br />

sein, d.h. der Rechner des KDC muss in einem gut verschlossenen Raum sein.<br />

¯ TGS stellt einem Client C während einer Sitzung Tickets für Authentifizierungen<br />

mit speziellen Servern des verteilten Systems zur Verfügung.<br />

Sicherheitsobjekte in Kerberos<br />

Kerberos realisiert die Authentifizierung mittels dreier Sicherheitsobjekte<br />

1. TGS-Ticket<br />

ausgestellt von KDC an Client C zur Präsentation beim TGS. Ein TGS-<br />

Ticket sagt aus, dass Client C erst vor kurzem durch Kerberos authentifiziert<br />

wurde. Das TGS-Ticket ist zeitlich beschränkt; es beinhaltet auch einen<br />

Sitzungsschlüssel für die gemeinsame Sitzung zwischen Client und TGS.<br />

2. Authentifizierer<br />

erzeugt durch Client C; dient zum Identitätsnachweis des Client sowie der<br />

zeitlichen Gültigkeit der Kommunikation mit dem Server S. Durch die<br />

zeitliche Beschränkung sollen Replays einer bereits früher stattgefundenen<br />

Kommunikation mit Server S unterbunden werden. Das Authentifizierer Objekt<br />

beinhaltet den Namen von C sowie einen Zeitstempel; beides wird mit dem<br />

Sitzungsschlüssel verschlüsselt.<br />

241


Schlichter, TU München 8.4. SICHERHEIT IN VERTEILTEN SYSTEMEN<br />

3. Sitzungsschlüssel<br />

erzeugt durch Kerberos für die Kommunikation zwischen Client C und<br />

Server S. Der Sitzungsschlüssel ist gültig für eine Sitzung. Er dient<br />

zur Verschlüsselung der Anforderungen und Antworten. Für nachfolgende<br />

Sitzungen muss von Kerberos ein neuer Sitzungsschlüssel erzeugt werden.<br />

Protokollablauf zur Authentifizierung<br />

¯ Nachricht 1<br />

1<br />

request<br />

TGS ticket<br />

KDC<br />

C<br />

TGS<br />

ticket<br />

2<br />

6<br />

Kerberos<br />

request Server 4<br />

ticket<br />

Server ticket<br />

3<br />

Authentifizierer<br />

Authentifizierer<br />

C KDC mit Information C, TGS<br />

Der Client C möchte von TGS für die weitere Kommunikation im verteilten<br />

System ein Ticket bekommen. Der Client C kann hier ein System oder auch ein<br />

Benutzer sein. TGS ist der Service, von dem die Tickets für die gewünschten<br />

Server erhalten werden sollen.<br />

5<br />

TGS<br />

– KDC bestimmt aus seiner Datenbank den geheimen Schlüssel k(C) für<br />

die Kommunikation zwischen Kerberos und C; KDC erzeugt einen guten<br />

zufälligen Sitzungsschlüssel k(C, tgs). Der Schlüssel k(C, tgs) gilt nur<br />

für eine Sitzung von C. Gut bedeutet in diesem Zusammenhang, dass der<br />

Schlüssel nur den beiden Kommunikationspartnern bekannt ist. k(C) ist der<br />

geheime Schlüssel von C, z.B. falls C ein Benutzer ist, dient das Passwort als<br />

geheimer Schlüssel k(C).<br />

242<br />

S


Schlichter, TU München 8.4. SICHERHEIT IN VERTEILTEN SYSTEMEN<br />

¯ Nachricht 2<br />

KDC C mit Information (k(C, tgs)) k(C)<br />

(C, TGS, T kdc ,L kdc , k(C, tgs)) k(tgs)<br />

= ticket(C, TGS) k(tgs)<br />

– geheimer Schlüssel k(C) wird aus dem Passwort des Benutzers abgeleitet;<br />

– zweiter Teil der Nachricht wird von C nicht interpretiert, sondern als Ganzes<br />

an TGS übergeben (d.h. TGS-Ticket). Das Ticket ist mit dem geheimen<br />

Schlüssel k(tgs) des TGS verschlüsselt.<br />

T Zeitstempel für Erzeugung des Tickets<br />

kdc<br />

L Lebensdauer des Tickets<br />

kdc<br />

Das Ticket beinhaltet neben dem Namen des Client auch dessen Adresse<br />

im verteilten System. In Kerberos sind als Lebensdauer für ein TGS-Ticket<br />

etwa 8 Stunden vorgesehen. Innerhalb der Gültigkeitsdauer kann C das<br />

Ticket beliebig oft zur Ticketanforderung für spezielle Server an TGS senden.<br />

Falls ein Ticket gestohlen wird, kann es nur für eine begrenzte Zeit genutzt<br />

werden. Ein Ticket ist mit dem geheimen Schlüssel von TGS und Kerberos<br />

verschlüsselt. Die Trennung von KDC und TGS erfolgt deshalb, damit<br />

Nachrichten, die mit einem vom Benutzerpasswort abgeleiteten Schlüssel<br />

verschlüsselt sind, möglichst selten über das Netz übertragen werden. Der<br />

Client C muss das Benutzerpasswort nicht lokal speichern.<br />

¯ Nachricht 3<br />

C TGS mit Information (C, T )<br />

C k(C,tgs)<br />

ticket(C, TGS)<br />

k(tgs)<br />

S<br />

Der 1. Teil der Nachricht dient als Authentifizierer für C. Dieser wird im<br />

Gegensatz zum Ticket für TGS nur einmal benutzt (deshalb Verwendung<br />

von T ). Bei der Festlegung von T muss die Übertragungsverzögerung<br />

C C<br />

mitberücksichtigt werden. S bezeichnet den gewünschten Server; die<br />

Komponente C beinhaltet hier wieder die Adresse von C im verteilten System.<br />

– TGS bestimmt einen zufälligen Sitzungsschlüssel k(C,S), falls<br />

TGS-Ticket noch gültig ist,<br />

243


Schlichter, TU München 8.4. SICHERHEIT IN VERTEILTEN SYSTEMEN<br />

¯ Nachricht 4<br />

T noch aktuell ist, und<br />

C<br />

das Feld C übereinstimmt (im 1. Parameter und Ticket).<br />

TGS C mit Information (k(C, S)) k(C, tgs)<br />

(C, S, T tgs , L tgs , k(C, S)) k(S) =<br />

ticket(C, S) k(S)<br />

– Der 2. Teil der Nachricht dient als Ticket von C für Server S.<br />

– k(S) ist der Kerberos bekannte geheime Schlüssel des Server's S. Das Ticket<br />

beinhaltet auch eine Gültigkeitsdauer, die von TGS bestimmt wird. C<br />

speichert Ticket und Sitzungsschlüssel in einem sicheren Speicherbereich.<br />

¯ Nachricht 5<br />

Die Nachrichten 5 und 6 dienen für C und S zur gegenseitigen Authentifizierung<br />

C S mit Information (C, T C ) k(C,S)<br />

ticket(C, S) k(S)<br />

Der 1. Teil der Nachricht dient wieder als Authentifizierer für C. Falls<br />

Überprüfung des Feldes C positiv ist, und das Ticket noch gültig ist, akzeptiert<br />

S den Schlüssel k(C,S) als authentifizierten Sitzungsschlüssel.<br />

¯ Nachricht 6<br />

S C mit Information (T C ) k(C,S)<br />

Die Nachricht dient für C zur Authentifizierung von S. Die weitere<br />

Kommunikation zwischen C und S erfolgt nun über den geheimen, temporären<br />

Sitzungsschlüssel. Man bezeichnet T c oft auch als "nonce".<br />

Problem von Kerberos<br />

Manipulation der lokalen Uhren der Rechner zur Umgehung der Gültigkeitsdauer<br />

von Tickets, d.h. Synchronisation der Uhren im verteilten System muss autorisiert<br />

und authentifiziert durchgeführt werden.<br />

244


Schlichter, TU München 8.4. SICHERHEIT IN VERTEILTEN SYSTEMEN<br />

Beispiel: Benutzerlogin mit Kerberos<br />

1. login Programm der Workstation W sendet Benutzername N an KDC<br />

2. falls Benutzer bekannt, sendet KDC einen Sitzungsschlüssel k(N) verschlüsselt<br />

mit dem Benutzerpasswort sowie ein TGS-Ticket.<br />

3. login Programm fordert Passwort von Benutzer an und entschlüsselt damit<br />

den Sitzungsschlüssel k(N); falls Passwort korrekt, stimmen entschlüsselter<br />

Sitzungsschlüssel k(N) und Sitzungsschlüssel k(N) in TGS-Ticket überein;<br />

4. Passwort kann aus Arbeitsspeicher von W entfernt werden, da für weitere<br />

Kommunikation nur k(N) und TGS-Ticket verwendet werden; beide dienen nun<br />

zur Authentifizierung bei TGS, falls Benutzer einen Server S benötigt.<br />

5. einrichten einer login-Sitzung des Benutzers an Workstation W. Das Passwort<br />

wird nicht über das Netz geschickt, im Gegensatz zur Basisauthentifizierung<br />

im WWW. Das Passwort wird aus dem Arbeitsspeicher sofort entfernt, falls<br />

TGS-Ticket und Sitzungsschlüssel vorhanden sind.<br />

Animation Kerberos<br />

siehe online Version<br />

8.4.5 Mobiler Code<br />

Das Internet führt zunehmend zu einer Verbreitung von mobilem Code. Beispiele<br />

sind<br />

Web Seiten mit Applets<br />

Postscript Dateien<br />

mobile Software-Agenten (z.B. in Ecommerce Anwendungen).<br />

Ausführung von heruntergeladenem Code birgt Risiken in sich. Beispielsweise<br />

kann ein Applet bösartigen Code enthalten, das auf Ressourcen der lokalen Umgebung<br />

zugreift und sie unberechtigterweise modifiziert oder löscht. Methoden (anhand<br />

von Applets), um mit dieser Problematik umzugehen:<br />

Sandboxing<br />

Ausführung des Applets wird auf einen bestimmten virtuellen Adressbereich<br />

beschränkt.<br />

245


Schlichter, TU München 8.4. SICHERHEIT IN VERTEILTEN SYSTEMEN<br />

Für eine Sandbox sind die high-order Bits aller Adressen gleich, d.h.<br />

angenommen für einen 32 Bit Adressraum werden 256 Sandboxes auf 16<br />

MByte Grenzen eingerichtet<br />

für alle Adressen innerhalb einer Sandbox sind die oberen 8 Bits<br />

identisch.<br />

¯ jedes Applet erhält zwei Sandboxes: eine Code-Sandbox, eine Daten-Sandbox.<br />

Die Code-Sandbox darf durch das Applet nicht verändert werden, um die<br />

Gefahr durch einen sich selbst-modifizierenden Code zu eliminieren.<br />

¯ nach dem Laden wird Applet-Code überprüft, ob er Befehle enthält,<br />

die ein Verlassen der Sandbox verursachen. Es werden insbesondere<br />

Sprungbefehle (JMP) und Systemaufrufe (CALL) untersucht. Sprungbefehle,<br />

deren Sprungziele erst zur Laufzeit bestimmt werden, können erst vor deren<br />

Ausführung analysiert werden.<br />

¯ ein Applet, das die Sandbox-Grenzen verletzt, wird zurückgewiesen.<br />

Interpretation<br />

Applet wird als Byte-Code geladen. Jeder Befehl wird vor seiner Ausführung von<br />

der Java Virtual Machine (JVM) analysiert.<br />

¯ jeder Systembefehl wird abgefangen und untersucht. Wie die einzelnen<br />

Systembefehle behandelt werden, hängt von der eingestellten Sicherheits-<br />

Policy ab.<br />

für vertrauenswürdige Applets (z.B. geladen von lokaler Festplatte) werden<br />

Systembefehle ausgeführt.<br />

nicht vertrauenswürdige Applets (z.B. geladen über Internet) werden<br />

innerhalb einer Sandbox ausgeführt.<br />

Signed Code<br />

Es werden nur Applets von vertrauenswürdigen Quellen geladen und ausgeführt.<br />

Applets anderer Quellen werden abgelehnt. Der Applet-Code wird mit<br />

einer digitalen Unterschrift versehen, um zu garantieren, dass der Code der<br />

vertrauenswürdigen Quelle nicht verändert wurde.<br />

¯ digitale Unterschrift basiert auf public-key Verfahren.<br />

246


Schlichter, TU München 8.4. SICHERHEIT IN VERTEILTEN SYSTEMEN<br />

¯ Erzeugung der Unterschrift durch vertrauenswürdige Quelle<br />

Hashfunktion erzeugt von Applet-Code eine 128/160 bit Zahl.<br />

erzeugte Hashzahl wird mit privatem Schlüssel der Quelle verschlüsselt.<br />

digitale Unterschrift wird mit Applet-Code verschickt.<br />

¯ Überprüfung der Unterschrift<br />

Browser führt auf Applet-Code Hashfunktion aus und berechnet selbst<br />

Hashzahl.<br />

Browser entschlüsselt Unterschrift mit öffentlichem Schlüssel der vertauenswürdige<br />

Quelle.<br />

berechnete Hashzahl und Hashzahl in Unterschrift müssen übereinstimmen.<br />

Falls die beiden Hashzahlen nicht übereinstimmen, wird die Ausführung des<br />

Applets abgelehnt.<br />

247


Kapitel 9<br />

Zusammenfassung<br />

Diese Vorlesung beschäftigte sich mit den technischen Aspekten von Rechensystemen.<br />

Es gab eine Einführung in systemnahe <strong>Programmierung</strong>. Dabei wurden<br />

sowohl nicht verteilte als auch verteilte Systeme betrachtet. Insbesondere wurden<br />

folgende Aspekte behandelt:<br />

Aufbau von Assemblerprogrammen und hardwarenahen Datenstrukturen.<br />

Modellierung von Prozessen, z.B. Petrinetze, sowie die Synchronisation von<br />

Prozessen beim Zugriff auf gemeinsame Ressourcen.<br />

Verwaltung von Prozessen und deren Zuteilung an den Rechnerkern, um sie<br />

auszuführen.<br />

Verwaltung des Arbeitsspeichers aus der Sicht des Betriebssystems (virtuelle<br />

Speicherverwaltung, Seitenadressierung).<br />

persistente Speicherung von Information in Dateien.<br />

Prozesskommunikation in lokalen und verteilten Systemen.<br />

Sicherheit in zentralen und verteilten Systemen.<br />

248

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!