Lehrgebiet Programmiersysteme Prof. Dr. Friedrich Steimann Kurs 01618 Einführung in die objektorientierte Programmierung _________________________________________________________ (Name, Vorname) _________________________________________________________ (Kursdurchführung des Sommersemester 2017) _________________________________________________________ (Straße, Nr.) ______________ (PLZ) Klausur am 16.09.2017 ________________________________________ (Wohnort) Zweistündige Klausur (10.00 – 12.00 Uhr) _________________________________________________________ (Land, falls außerhalb Deutschlands) Lesen Sie zuerst die Hinweise auf der folgenden Seite! Matrikelnummer: Geburtsdatum: . . Klausurort: _________________________ Aufgabe 1 2 3 4 5 6 7 8 Summe 10 10 10 10 10 10 10 10 80 habe bearbeitet maximal erreicht Korrektur ○ ○ Herzlichen Glückwunsch, Sie haben die Klausur bestanden. Note: .......... Sie haben die Klausur leider nicht bestanden. Für den nächsten Versuch wünschen wir Ihnen viel Erfolg. Die nächste Klausur findet im Wintersemester 2017 / 2018 statt. MUSTERLÖSUNG Hagen, den 27.09.2017 Im Auftrag © 2017 FernUniversität in Hagen Lehrgebiet Programmiersysteme Prof. Dr. Friedrich Steimann Klausur zum Kurs 01618 im Sommersemester 2017 Aufgabe 1: Klassenimplementierung (10 Punkte) Gegeben sei das folgende Programmfragment: public class HeimkinoDemo { public static void main(String[] args) { TonSystem m = new TonSystem(2); BluRayPlayer t = new BluRayPlayer(); TvGerät c = new TvGerät(t, m); c.bluRayPlayer.einlegen(new BluRayMedium("Star Wars")); try { c.tonSystem.erwarteKanäle(6); System.out.println("Surround-Sound-Tonsystem."); } catch (Exception e) { System.out.println("Kein Surround-Sound Tonsystem."); } try { c.tonSystem.erwarteKanäle(2); System.out.println("Stereo-Tonsystem."); } catch (Exception e) { System.out.println("Kein Stereo-Tonsystem."); } } } Geben Sie Implementierungen für die Klassen TonSystem, BluRayPlayer, BluRayMedium und TvGerät an, sodass dieses Programmfragment kompiliert werden kann und bei Terminierung der main-Methode die folgenden Zeilen auf der Konsole ausgegeben werden. Tonsystem mit 2 Kanälen erzeugt. Film 'Star Wars' eingelegt. Kein Surround-Sound Tonsystem. Stereo-Tonsystem. Diese Zeichenketten sollen selbstverständlich durch die jeweiligen Anweisungen zusammengesetzt und ausgegeben werden. (Fortsetzung der Aufgabe auf der folgenden Seite) Seite 1 Klausur zum Kurs 01618 im Sommersemester 2017 Lehrgebiet Programmiersysteme Prof. Dr. Friedrich Steimann (Fortsetzung von Aufgabe 1) class TvGerät { BluRayPlayer bluRayPlayer; TonSystem tonSystem; public TvGerät(BluRayPlayer bluRayPlayer, TonSystem hiFiSystem) { this.bluRayPlayer = bluRayPlayer; this.tonSystem = hiFiSystem; } } class BluRayPlayer { public void einlegen(BluRayMedium medium) { System.out.println("Film '" + medium.titel + "' eingelegt."); } } class BluRayMedium { String titel; public BluRayMedium(String titel) { this.titel = titel; } } class TonSystem { private int kanäle; public TonSystem(int kanäle) { this.kanäle = kanäle; System.out.println("Tonsystem mit " + kanäle + " Kanälen erzeugt."); } public void erwarteKanäle(int erwarteteKanäle) throws Exception { if (kanäle != erwarteteKanäle) throw new Exception(); } } Seite 2 Lehrgebiet Programmiersysteme Prof. Dr. Friedrich Steimann Klausur zum Kurs 01618 im Sommersemester 2017 Aufgabe 2: (Beschränkt) param. Polymorphie (10 Punkte) Gegeben sei das folgende Programmfragment: public class Wohnzimmer { public static void main(String[] args) { Kiste kiste = new Kiste(); Regal regal = new Regal(); Brettspiel schach = new Brettspiel(kiste); Buch herrDerRinge = new Buch(regal); Gegenstand<?> einGegenstand = schach; Möbelstück möbel = einGegenstand.lagerort(); Kiste spieleKiste = schach.lagerort(); Regal bücherRegal = herrDerRinge.lagerort(); /* [1] */ // Fehler in Aufgabe: // schach statt spiel // schach statt spiel // herrDerRinge statt buch } } class Möbelstück { } class Kiste extends Möbelstück { } class Regal extends Möbelstück { } Geben Sie eine Implementierung für die Klassen Gegenstand, Brettspiel und Buch an, sodass dieses Programmfragment kompiliert. Die Methode lagerort() soll insgesamt nur ein einziges Mal implementiert werden. (5 Punkte) Hinweis: In der Aufgabenstellung haben sich zwei kleine Fehler eingeschlichen (s.o.). Obwohl sich der nachfolgende Lösungsvorschlag hierdurch nicht ändert, wurde das bei der Korrektur Ihrer Lösungen berücksichtigt. abstract class Gegenstand<T extends Möbelstück> { T lagerort; public Gegenstand(T lagerort) { this.lagerort = lagerort; } T lagerort() { return lagerort; } } class Brettspiel extends Gegenstand<Kiste> { public Brettspiel(Kiste lagerort) { super(lagerort); } } class Buch extends Gegenstand<Regal> { public Buch(Regal lagerort) { super(lagerort); } } (Fortsetzung der Aufgabe auf der folgenden Seite) Seite 3 Klausur zum Kurs 01618 im Sommersemester 2017 Lehrgebiet Programmiersysteme Prof. Dr. Friedrich Steimann (Fortsetzung von Aufgabe 2) Die main-Methode wird nun an der mit /* [1] */ markierten Stelle um die folgenden Zeilen ergänzt: Kiste andereKiste = new Kiste(); Brettspiel dame = new Brettspiel(andereKiste); schach.tauschePlatz(dame); Regal anderesRegal = new Regal(); Buch harryPotter = new Buch(anderesRegal); herrDerRinge.tauschePlatz(harryPotter); Während diese zwei Aufrufe von tauschePlatz(.) durch den Compiler akzeptiert werden sollen, soll der Aufruf von herrDerRinge.tauschePlatz(schach); zurückgewiesen werden. Geben Sie eine (einzige) Implementierung der Methode tauschePlatz(.) an, die diese Kriterien erfüllt. In welcher Klasse steht diese? (2,5 Punkte) abstract class Gegenstand<T extends Möbelstück> { … public void tauschePlatz(Gegenstand<T> andererGegenstand) { T andererLagerort = andererGegenstand.lagerort(); andererGegenstand.lagerort = this.lagerort; this.lagerort = andererLagerort; } } Erklären Sie, warum der Compiler den letztgenannten Aufruf zurückweist. (2,5 Punkte) Das durch herrDerRinge referenzierte Objekt ist vom Typ Gegenstand<Regal> - der Typparameter T der Klasse Gegenstand ist also mit dem Typen Regal belegt. Die Implementierung der Methode tauschePlatz erwartet ein Objekt vom Typ Gegenstand, bei dem der Typparameter mit dem gleichen Typen belegt ist wie in dem Empfängerobjekt; in diesem Fall also ebenfalls Regal. Das durch schach referenzierte Objekt hingegen ist vom Typ Gegenstand<Kiste>, der Typparameter T von Gegenstand ist also mit Kiste belegt. Zwischen Gegenstand<Regal> und Gegenstand<Kiste> besteht jedoch keine Subtypbeziehung. Der aktuelle Parameter schach kann also nicht dem formalen Parameter andererRegenstand zugewiesen werden, wenn das Empfängerobjekt herrDerRinge ist. Hinweis: Das bedeutet nicht, dass der Gegenstand, welcher der Methode tauschePlatz übergeben wird, vom gleichen Typ sein muss wie der, auf dem sie aufgerufen wird. Gleich sein müssen nur die Möbelstücke, mit denen die beiden Gegenstände parametrisiert wurden. Wenn es beispielsweise eine Klasse "Vase extends Gegenstand<Regal>" gäbe, könnte eine Vase problemlos ihren Platz mit einem Buch tauschen. Seite 4 Klausur zum Kurs 01618 im Sommersemester 2017 Aufgabe 3: Subtyping Was besagt die Grundregel des Subtyping? Lehrgebiet Programmiersysteme Prof. Dr. Friedrich Steimann (10 Punkte) (2 Punkte) (Abs. 3.2.2.2) „Die Grundregel für Subtyping besagt, dass ein Objekt von einem Subtyp an allen Programmstellen vorkommen kann, an denen Supertyp-Objekte zulässig sind.“ Welche syntaktischen Voraussetzungen müssen erfüllt sein, wenn in einer Subklasse eine geerbte Methode überschrieben werden soll? (3 Punkte) (vgl. Abs. 3.2.2.2) Um eine Methode zu überschreiben, muss in der Subklasse eine Methode gleichen Namens deklariert werden. Weiterhin müssen die Typen von Parametern, Rückgabeparametern und Ausnahmen der überschreibenden Methode zu denen der überschriebenen passen; d.h.: Theoretisch: Kontravarianz bei Parametertypen; Kovarianz bei Rückgabe- und Ausnahmetypen. für Java >= 5: Gleichheit der Parametertypen, Kovarianz bei Rückgabe- und Ausnahmetypen. (Kontravarianz der Parametertypen wird in Java nicht unterstützt, da es andernfalls bei überladenen Methoden zu Konstellationen kommen kann, in denen der Compiler einen Methodenaufruf nicht eindeutig an eine Deklaration binden kann.) für Java < 5: Gleichheit von Parameter- und Rückgabetypen Ist es ausreichend, die syntaktischen Voraussetzungen zu überprüfen, um sicherzustellen, dass ein Typ ein Subtyp ist? Welche besondere Herausforderung liegt hierin für den Programmierer / die Programmiererin? (5 Punkte) (vgl. Abs. 3.2.2.2) Nein, das Konzept des Subtyping beschränkt sich nicht auf syntaktischer Konformität von Methodendeklarationen. Die Eigenschaft, dass ein Objekt eines Subtyps überall dort eingesetzt werden kann, wo ein Objekt eines Supertyps erwartet wird, stellt vielmehr auch die Forderung an das Verhalten des Objektes, dass es den Erwartungen genügen muss, die an den Supertypen gestellt werden. Nur, wenn diese Erwartungen durch den Subtyp nicht verletzt werden, verhält dieser sich konform und ist damit ein Subtyp. Dies sicher zu stellen ist Aufgabe des Programmierers / der Programmiererin, da in der Regel keine formale Verhaltensspezifikation vorliegt bzw. geprüft werden kann. Seite 5 Klausur zum Kurs 01618 im Sommersemester 2017 Aufgabe 4: Polymorphie Lehrgebiet Programmiersysteme Prof. Dr. Friedrich Steimann (10 Punkte) Welche vier Arten von Polymorphie kennen Sie? (2 Punkte) Subtyp-Polymorphie parametrische Polymorphie beschränkt parametrische Polymorphie (hierbei handelt es sich um eine spezielle Form der parametrischen Polymorphie) Ad-hoc Polymorphie Charakterisieren Sie jede Art kurz! (jeweils 2 Punkte) Subtyp-Polymorphie wird durch Subtyping erreicht. Das bedeutet, dass an den Stellen, an denen ein Objekt vom Typ Typ erwartet wird, auch Objekte beliebiger Typen Subtyp stehen dürfen, sofern diese Subtypen von Typ sind. Parametrische Polymorphie wird dadurch realisiert, dass bestimmte Konstrukte einer Programmiersprache – z.B. Methoden oder Klassen – durch Typparameter parametrisiert werden. Bei der Verwendung eines so parametrisierten Konstrukts wird der Typparameter durch einen konkreten Typen ersetzt. So ist es möglich, eine generische Implementierung einer Funktionalität anzugeben, die in verschiedenen Kontexten typsicher genutzt werden kann. Die beschränkt parametrische Polymorphie begegnet dem Problem der (einfachen) parametrischen Polymorphie, dass innerhalb der generischen Klasse keine Informationen über den Typen, mit dem der Typparameter belegt wird, zur Verfügung stehen. Hierin können so ohne eine explizite Typkonvertierung (Type Casts) keine spezifischen Methoden verwendet werden. Durch die Angabe einer Schranke zu dem Typparameter kann nun hingegen festgelegt werden, dass dieser lediglich durch Subtypen der Schranke belegt werden kann. So kann auch ohne Typkonvertierung (Type Cast) innerhalb der generischen Implementierung auf die durch die Schranke deklarierte Schnittstelle zugegriffen werden. Als Ad-hoc Polymorphie wird das Überladen von Operatoren bzw. Methodennamen bezeichnet. Für identifizierte Operationen können so für unterschiedliche Argumenttypen jeweils optimierte Implementierungen angegeben werden. Seite 6 Lehrgebiet Programmiersysteme Prof. Dr. Friedrich Steimann Klausur zum Kurs 01618 im Sommersemester 2017 Aufgabe 5: Arrays (10 Punkte) Gegeben sei das folgende Programmfragment, welches die Zahlen 𝑛 mit 1 ≤ 𝑛 ≤ 𝑚𝑎𝑥 in Hexadezimalnotation konvertieren, in ein Array speichern und ausgeben soll: public class ArrayDemo { public static void main(String[] args) { int max = Integer.parseInt(args[0]); /* [1] */ /* [2] */ /* [3] */ } } Teilaufgabe a: Erste Implementierung (4 Punkte) Hinweis: Die statische Bibliotheksfunktion Integer.toHexString(int) konvertiert die per Parameter angegebene Zahl in Hexadezimalnotation. So liefert Integer.toHexString(11) etwa die Zeichenkette “b“. Wodurch muss /* [1] */ ersetzt werden, um das (eindimensionale) Array mit dem Namen zahlen zu initialisieren? (1 Punkt) String[] zahlen = new String[max]; Wodurch muss /* [2] */ ersetzt werden, um die Hexadezimalnotationen aller 𝑛 mit 1 ≤ 𝑛 ≤ 𝑚𝑎𝑥 in dieses Array zu schreiben? Bitte verwenden Sie eine Schleife! (2 Punkte) for (int i = 1; i <= max; i++) { zahlen[i - 1] = Integer.toHexString(i); } Wodurch muss /* [3] */ ersetzt werden, um den Inhalt des Arrays auf die Konsole zu schreiben? Bitte verwenden Sie eine Schleife – und zwar eine Schleife einer anderen Art als die, die Sie in Ihrer Implementierung zur Ersetzung von /* [2] */ verwendet haben! (1 Punkt) for (String i : zahlen){ System.out.println(i); } (Fortsetzung der Aufgabe auf der folgenden Seite) Seite 7 Klausur zum Kurs 01618 im Sommersemester 2017 Lehrgebiet Programmiersysteme Prof. Dr. Friedrich Steimann (Fortsetzung von Aufgabe 5) Teilaufgabe b: Zweite Implementierung (6 Punkte) In der zweiten Implementierung soll nun nicht nur die Hexadezimalnotation einer Zahl gespeichert werden, sondern auch ihre Binärnotation. Dazu soll ein zweidimensionales Array (also ein Array von Arrays) verwendet werden. Hinweis: Analog zu Integer.toHexString(int) existiert auch eine Methode Integer.toBinaryString(int), die der Konvertierung einer Zahl in Binärnotation dient; so liefert Integer.toBinaryString(73) etwa die Binärnotation von 73, also die Zeichenkette „1001001“. Wodurch muss /* [1] */ ersetzt werden, um das Array mit dem Namen zahlen zu initialisieren, welches aus Arrays der Dimension 2 besteht? (2 Punkt) String[][] zahlen = new String[max][2]; Wodurch muss /* [2] */ ersetzt werden, um die Paare Binär- und Hexadezimalnotation in dieses Array zu schreiben? Bitte verwenden Sie eine Schleife! (2 Punkte) for (int i = 1; i <= max; i++) { zahlen[i - 1][0] = Integer.toBinaryString(i); zahlen[i - 1][1] = Integer.toHexString(i); } Wodurch muss /* [3] */ ersetzt werden, um die Zahlen in Binär- und Hexadezimalnotation (genauer: in dem Format „x : y“, wobei x die Binär- und y die Hexadezimanotation ist) auf die Konsole zu schreiben? Bitte verwenden Sie eine Schleife – und zwar eine Schleife einer anderen Art als die, die Sie in Ihrer Implementierung zur Ersetzung von /* [2] */ verwendet haben. (2 Punkt) for (String[] i : zahlen){ System.out.println(i[0] + " : " + i[1]); } Seite 8 Lehrgebiet Programmiersysteme Prof. Dr. Friedrich Steimann Klausur zum Kurs 01618 im Sommersemester 2017 Aufgabe 6: Kontrollfluss und der this-Parameter (10 Punkte) Gegeben sei folgendes Java-Programm: public class EineNeueKlasse { String tier = "Pinguin"; public static void main(String[] args) { new EineNeueKlasse("Biene").m(42L); } EineNeueKlasse(String tier) { System.out.println(this.tier); } void m(Number n){ System.out.println("Esel"); new WeitereInnereKlasse().methode(new SubInnereKlasse("Giraffe")); } void m(Long l) { System.out.println("Löwe"); new WeitereInnereKlasse().methode(new SubInnereKlasse("Giraffe")); } class InnereKlasse { String tier = "Elefant"; InnereKlasse(String tier) { System.out.println(this.tier); } void n(WeitereInnereKlasse weitereInnere) { System.out.println("Hund"); } void n(EineNeueKlasse eineNeue) { System.out.println("Hamster"); } } class SubInnereKlasse extends InnereKlasse{ String tier = "Adler"; public SubInnereKlasse(String tier) { super("Hase"); System.out.println(tier); } } static class WeitereInnereKlasse { { System.out.println("Bär"); /* [2] */ } void methode(InnereKlasse innereKlasse) { innereKlasse.n(this); } } static void andereMethode() { /* [1] */ } } (Fortsetzung der Aufgabe auf der folgenden Seite) Seite 9 Klausur zum Kurs 01618 im Sommersemester 2017 Lehrgebiet Programmiersysteme Prof. Dr. Friedrich Steimann (Fortsetzung von Aufgabe 6) Welche Zeilen wurden nach Terminierung der main(.)-Methode auf der Konsole ausgegeben? (6 Punkte) Pinguin Löwe Bär Elefant Giraffe Hund An der mit /* [1] */ markierten Stelle wird die folgende Anweisung eingefügt. Warum weist der Compiler sie zurück? System.out.println(this.tier); (2 Punkte) Die mit andereMethode bezeichnete Methode, in deren Rumpf diese Anweisung eingefügt wird, ist statisch. Sie ist damit keinem Objekt zugeordnet und hat insbesondere keinen impliziten thisParameter, welcher ja immer ein Objekt als Instanz einer Klasse referenziert. In der Konsequenz kann auch tier nicht referenziert werden, da es ein Objekt- und kein Klassenattribut ist. Das Programm ist somit ungültig. An der mit /* [2] */ markierten Stelle wird die folgende Anweisung eingefügt. Warum weist der Compiler sie zurück? System.out.println(EineNeueKlasse.this.tier); (2 Punkte) Der Initialisierungsblock, in den diese Anweisung eingefügt werden soll, gehört zu der inneren Klasse WeitereInnereKlasse, welche static deklariert ist. Als solche ist sie – wie auch statische Methoden – nicht einem Objekt der umschließenden Klasse EineNeueKlasse zugeordnet, sondern der Klasse selbst. Eine Instanz der umschließenden Klasse EineNeueKlasse, welche mit EineNeueKlasse.this referenziert werden könnte, existiert somit gar nicht und das Programm ist ungültig. Seite 10 Lehrgebiet Programmiersysteme Prof. Dr. Friedrich Steimann Klausur zum Kurs 01618 im Sommersemester 2017 Aufgabe 7: Aufzählungstypen (10 Punkte) Die Monate der Freibadsaison (Mai bis September) sollen als Aufzählungstyp SaisonMonat implementiert werden. Die Werte des Aufzählungstypen sollen über die folgenden vier Methoden verfügen: boolean istNach(SaisonMonat monat): Liefert true, wenn der durch das Empfängerobjekt bezeichnete Monat nach dem Monat liegt, der durch das Objekt bezeichnet wird, welches durch den Parameter monat referenziert wird; ansonsten false. (Wobei angenommen wird, dass beide Objekte für Monate des gleichen Jahres stehen.) boolean istVor(SaisonMonat monat): Liefert true, wenn der durch das Empfängerobjekt bezeichnete Monat vor dem Monat liegt, der durch das Objekt bezeichnet wird, welches durch den Parameter monat referenziert wird; ansonsten false. (Wobei angenommen wird, dass beide Objekte für Monate des gleichen Jahres stehen.) SainsonMonat naechsterSaisonMonat(): Liefert das Element der Aufzählung, welches den Monat beschreibt, der unmittelbar nach dem durch das Empfängerobjekt bezeichneten Monat liegt; wobei dies auch der erste Monat des folgenden Jahres sein kann. SainsonMonat vorherigerSaisonMonat(): Liefert das Element der Aufzählung, welches den Monat beschreibt, der unmittelbar vor dem durch das Empfängerobjekt bezeichneten Monat liegt; wobei dies auch der letzte Monat der vorherigen Saison sein kann. Die main-Methode der Klasse FreibadSaisonDemo verdeutlicht die Bedeutung der Methoden anhand einiger Beispiele. Der in jeder Zeile hinten angefügte Kommentar gibt dabei jeweils den Wert an, zu dem der Ausdruck dieser Zeile auswerten soll. public class FreibadSaisonDemo { public static void main(String[] args) { SaisonMonat.JULI.istVor(SaisonMonat.MAI); SaisonMonat.JULI.istVor(SaisonMonat.JUNI); SaisonMonat.JULI.istVor(SaisonMonat.JULI); SaisonMonat.JULI.istVor(SaisonMonat.AUGUST); SaisonMonat.JULI.istVor(SaisonMonat.SEPTEMBER); // // // // // false false false true true SaisonMonat.JULI.istNach(SaisonMonat.JUNI); SaisonMonat.JULI.istNach(SaisonMonat.JULI); SaisonMonat.JULI.istNach(SaisonMonat.AUGUST); // true // false // false SaisonMonat.JULI.naechsterSaisonmonat(); SaisonMonat.JULI.vorherigerSaisonmonat(); // SaisonMonat.AUGUST // SaisonMonat.JUNI SaisonMonat.SEPTEMBER.naechsterSaisonmonat(); SaisonMonat.MAI.vorherigerSaisonmonat(); // SaisonMonat.MAI // SaisonMonat.SEPTEMBER } } Da das Freibad in Kürze in der Lage ist, das Wasser der Becken zu beheizen, zieht der Betreiber in Erwägung, die Saison auf die angrenzenden Monate April und Oktober auszudehnen. Vervollständigen Sie folgende Implementierung der Klasse FreibadSaison derart, dass die Methodenimplementierungen bei einer Erweiterung des Aufzählungstyps um die Elemente APRIL und OKTOBER nicht verändert werden müssen. (Fortsetzung der Aufgabe auf folgender Seite) Seite 11 Klausur zum Kurs 01618 im Sommersemester 2017 Lehrgebiet Programmiersysteme Prof. Dr. Friedrich Steimann (Fortsetzung von Aufgabe 7) enum SaisonMonat { MAI, JUNI, JULI, AUGUST, SEPTEMBER; (1 Punkt) boolean istNach(SaisonMonat monat) { // Hinweis: In der Methodenbeschreibung muss es korrekterweise heißen: // … Liefert true, wenn der durch das Empfängerobjekt bezeichnete Monat // nach dem Monat liegt, der … return this.ordinal() > monat.ordinal(); } (1 Punkt) boolean istVor(SaisonMonat monat) { // Hinweis: In der Methodenbeschreibung muss es korrekterweise heißen: // … Liefert true, wenn der durch das Empfängerobjekt bezeichnete Monat // vor dem Monat liegt, der … return this.ordinal() < monat.ordinal(); } (4 Punkte) SaisonMonat naechsterSaisonmonat() { int nächsterIndex = this.ordinal() + 1; if ( nächsterIndex == SaisonMonat.values().length) nächsterIndex = 0; return SaisonMonat.values()[ nächsterIndex ]; } (4 Punkte) SaisonMonat vorherigerSaisonmonat() { int vorherigerIndex = this.ordinal() - 1; if ( vorherigerIndex < 0) vorherigerIndex = SaisonMonat.values().length - 1; return SaisonMonat.values()[ vorherigerIndex ]; } } Seite 12 Klausur zum Kurs 01618 im Sommersemester 2017 Lehrgebiet Programmiersysteme Prof. Dr. Friedrich Steimann Aufgabe 8: Parallelität Welche Varianten lokaler Parallelität lassen sich unterscheiden? Erklären Sie sie! (10 Punkte) (3 Punkte) Reale Parallelität bedeutet, dass in einem einzigen System verschiedene Aktionen tatsächlich parallel ablaufen können. Virtuelle Parallelität (oder auch Quasi-Parallelität) hingegen bedeutet, dass Aktionen, die zwar echt parallel laufen könnten, zunächst sequentialisiert werden und nacheinander ausgeführt werden. So kann ein Softwaresystem auch auf einem Einprozessorsystem scheinbar parallel ausgeführt werden. Warum ist es auch dann von Vorteil, ein Softwaresystem so zu implementieren, dass es parallel ausgeführt werden kann, wenn es nur auf einem Einprozessorsystem laufen soll? (3 Punkte) Häufig ist es nicht notwendig, die Ausführungsreihenfolge zweier Aktionen a und b festzulegen; d.h. für die Funktionalität des Programms ist es äquivalent, ob zuerst a oder b ausgeführt wird. In diesem Fall erlaubt die Berücksichtigung der Parallelität, auf eine künstliche Sequentialisierung einer Implementierung zu verzichten und überlässt es einem Scheduler, zwischen verschiedenen Ausführungssträngen zu wechseln. Eine solche verschränkte Ausführung ist insbesondere dann von Vorteil, wenn ein Strang gerade nichts „Sinnvolles“ tun kann, da er z.B. auf eine Antwort aus dem Netzwerk oder einem Gerät (z.B. der Festplatte) wartet. Welche Aufgabe hat der Scheduler? Welche Arten des Schedulings können unterschieden werden? Wann ist das Scheduling fair? (4 Punkte) Der Scheduler hat die Aufgabe, die für die Programmausführung zur Verfügung stehenden Prozessoren den verschiedenen Ausführungssträngen zuzuteilen. Beim preemptiven Scheduling entscheidet der Scheduler darüber, wie lange ein Ausführungsstrang rechnen darf. So kann er dem Strang z.B. nach Ablauf eines bestimmten Zeitfensters den Prozessor entziehen und ihn einem anderen Strang zuweisen. Beim nicht-preemptiven Scheduling entscheidet ein Ausführungsstrang selbstständig darüber, wann er einen Prozessor wieder freigibt. Bei unvorsichtiger Implementierung kann dies dazu führen, dass ein Ausführungsstrang alle anderen blockiert. Das Scheduling ist dann fair, wenn der Scheduler garantiert, dass jeder Ausführungsstrang nach einer endlichen Wartezeit einen Prozessor zugeteilt bekommt. Seite 13