# https://sys.cs.fau.de/extern/lehre/ws23/sp2/pruefung/klausuren/2022w-SP-Klausur_www.pdf 0 Welche der folgenden Aussagen zu statischem bzw. dynamischem Binden ist richtig? (Februar 2022) - Statisch gebundene Programmdateien sind kleiner als dynamisch gebundene, da mehrfach genutzte Funktionen in einer shared library abgelegt werden und nicht in die ausführbare Datei kopiert werden Die Beschreibung trifft auf dynamisch gebundene Programmdateien, weil Bibliotheksfunktionen zur Laufzeit auf `.so` Dateien laden, im gegensatz zu statisch gebundenen Programmen, wo diese jedes mal zum Bindezeitpunkt in die ausführbare Datei kopiert werden. - Bei dynamischem Binden können Fehlerkorrekturen in Bibliotheken leichter übernommen werden, da nur die Bibliothek selbst neu erzeugt werden muss. Programme, die die Bibliothek verwenden, müssen nicht neu kompiliert und gebunden werden. Ja. Im Gegensatz dazu, müsste man bei einem statischen Bibliothek alle Programme nochmal neu, gegen die aktualisierte Bibliothek bauen, damit diese die neuste Version benutzen. - Beim statischen Binden werden alle Adressen zum Ladezeitpunkt aufgelöst Nein, Adressen werden alle beim Binden aufgelöst, und sind somit unabhängig von der Ausführung -- *statisch* -- bekannt. - Bei dynamischem Binden müssen zum Übersetzungszeitpunkt alle Adressbezüge vollständig aufgelöst werden Nein, Bibliotheksfunktionen welche aus *Shared Object* Dateien geladen werden können zur Laufzeit, müssen nicht beim Übersetzen bereits aufgelöst geworden sein. . 0 Welche Antwort trifft für die Eigenschaften eines UNIX/Linux-Dateideskriptor zu? (Februar 2022) - Ein Dateideskriptor ist eine Integerzahl, die über gemeinsamen Speicher an einen anderen Prozess übergeben werden kann, und von letzterem zum Zugriff auf eine geöffnete Datei verwendet werden kann. Nein, es ist zwar eine Ganzzahl, aber diese kann nicht beliebig hin und her gereicht werden, zumindest ohne dass das Betriebsystem entsprechend informiert wird (siehe `sendmsg(2)`). - Dateideskriptoren sind Zeiger auf Betriebssystemstrukturen, die von den Systemaufrufen ausgewertet werden, um auf Dateien zuzugreifen. Nein, es handelt sich nicht um einen Zeiger im gewöhnlichen Sinne (eine Adresse auf eine Speicherstelle), auch wenn es üblicherweise dazu benutzt wird um eine Prozess-Lokale Datei Tabelle zu Adressieren. Es stimmt aber, dass es dazu benutzt wird, einem Systemaufruf eine Datei anzudeuten, auf dem dieses arbeiten soll. + Ein Dateideskriptor ist eine prozesslokale Integerzahl, die der Prozess zum Zugriff auf eine Datei, ein Gerät, einen Socket oder eine Pipe benutzen kann. Ja, ein Dateideskriptor muss nicht nur auf "gewöhnlichen" Dateien arbeiten, sondern kann verschieden "Datei-Ähnlichen" Objekten (d.h. Datenströmen) abstrahieren. Wichtig ist auch der Punkt "prozesslokal", weil die Zahl nur eine Bedeutung hat, wenn das Betriebsystem dem Prozess diese Zahl zuvor explizit vergeben hat. - Beim Öffnen ein und derselben Datei erhält ein Prozess jeweils die gleiche Integerzahl als Dateideskriptor zum Zugriff zurück. Nein, es ist möglich eine Datei Mehrfach zu öffnen, und dabei mehrere Dateideskriptoren zu bekommen. Versuche ~~~ #include <fcntl.h> #include <unistd.h> #include <stdio.h> int main() { int fd1 = open("/etc/passwd", O_RDONLY); int fd2 = open("/etc/passwd", O_RDONLY); printf("fd1: %d, fd2: %d\n", fd1, fd2); } ~~~ . 1 Man unterschiedet zwei Kategorien von Ausnahmesituationen bei einer Programmausführung: Traps und Interrupts. Welche der folgenden Aussagen sind zutreffend? (Februar 2022) + Ein Programm darf im Rahmen einer Trapbehandlung abgebrochen werden. Ja, Beispielsweise bei einem ungültigem Speicherzugriff. + Ein durch einen Interrupt unterbrochenes Programm darf je nach der Interruptursache entweder abgebrochen oder fortgesetzt werden. Ja, so ist ein _Timer Interrupt_ nicht fatal, und aktiviert nur den Scheduler, während ein _Tastatur Interrupt_ so konfiguriert werden kann, dass ein Prozess unterbrochen wird (denke an `Ctrl-C`). - Bei einem Trap wird der gerade in Bearbeitung befindliche Maschinenbefehl immer noch vollständig zu Ende bearbeitet, bevor mit der Trapbehandlung begonnen wird. Nein, bspw. wenn man versucht auf nicht lesbaren Speicher versucht zuzugreifen, muss es abgebrochen werden, bevor auf den Speicher zuggegriffen wurde. + Die CPU sichert bei einem Interrupt einen Teil des Prozessorzustands. Ja, genau wie bei einer Signal-Behandlung unterbricht ein Interrupt das "Hauptprogramm" vom Betriebsystem. Der Prozessorzustand muss dafür vermerkt worden sein, damit es danach wieder restauriert werden kann. + Die Ausführung einer Ganzzahl-Rechenoperation (z. B. Addition, Division) kann zu einem Trap führen. Ja, eine Rechnerarchitektur kann beim Teilen durch 0 ein Trap auslösen. - Da Traps immer synchron auftreten, kann es im Rahmen ihrer Behandlung nicht zu Wettlaufsituationen mit dem unterbrochenen Programm kommen. Nein, weil Traps eben immer syncrhron auftreten, gibt es keine Nebenläufigkeit welche Probleme bereitet. ? Wenn ein Interrupt ein schwerwiegendes Ereignis signalisiert, wird das unterbrochene Programm im Rahmen der Interruptbearbeitung immer abgebrochen. - Ein Systemaufruf im Anwendungsprogramm ist der Kategorie Interrupt zuzuordnen. Nein, weil diese deterministisch immer dann auftreten, wenn ein Programm ein Systemaufruf absetzen will. . 0 In welcher der folgenden Situationen wird ein Prozess vom Zustand laufend in den Zustand bereit übeführt? (Februar 2022) - Der Prozess ruft die Bibliotheksfunktion `exit(3)` auf. Nein, weil danach der Prozess nicht mehr "bereit" ist (d.h. wieder eingelagert werden kann). + Der Scheduler bewirkt, dass der Prozess durch einen anderen Prozess verdrängt wird. Ja, weil die einzige Ressource welche dem Prozess fehlt ist die CPU, welche der Scheduler später wieder "vergeben" kann, und damit der Prozess auch die ganze Zeit bereit ist wieder weiter zu laufen. - Der Prozess greift lesend auf eine Datei zu und der entsprechende Datenblock ist noch nicht im Hauptspeicher vorhanden. Nein, weil dann idr. der Prozess beendet wird mit einem Sigal wie `SIGSEVG`, und nicht mehr laufen darf. - Der Prozess ruft eine P-Operation auf einen Semaphor auf, welcher den Wert 0 hat. Nein, weil dann der Prozess blokiert wird, und nicht mehr laufen kann, bis an einer anderen Stelle eine entsprechende V-Operation ausgeführt wird. . 0 Sie kennen den Translation-Lookaside-Buffer (TLB). Welche Aussage ist richtig? (Februar 2023) + Verändert sich die Speicherabbildung von logischen auf physikalische Adressen aufgrund einer Adressraumumschaltung, so werden auch die Daten im TLB ungültig. Ja, weil die zwischengespeicherten Seitenaddressen nicht mehr mit dem neuem logischem Addressraum zusammenhängen würden. - Der TLB verkürzt die Zugriffszeit auf den physikalischen Speicher da ein Teil des möglichen Speichers in einem schnellen Pufferspeicher vorgehalten wird. Nein, im TLB werden nur die Addressen der Seiten gespeichert, um das Nachschlagen in der MMU zu vermeiden, und nicht den Speicher selbst. - Der TLB puffert Daten bei der Ein-/Ausgabebehandlung und beschleunigt diese damit. Nein, der TLB hat nichts mit den Daten per se zu tun, sondern beschleundigt nur den Zugriff auf häufig benutzte Seiten. - Wird eine Speicherabbildung im TLB nicht gefunden, wird der auf den Speicher zugreifende Prozess mit einer Schutzraumverletzung (Segmentation Fault) abgebrochen. Nein, ist kein Eintrag im TLB zu finden, wird die Addresse von der MMU aufgelöst. . 0 Welche Aussage zu Prozessen und Threads ist richtig? (Februar 2023) - Mittels `fork()` erzeugte Kindprozesse können in einem Multiprozessor-System nur auf dem Prozessor ausgeführt werden, auf dem auch der Elternprozess ausgeführt wird. Nein, es ist dem Scheduler ganz überlassen zu entscheiden, auf welchen Prozessoren ein Prozess laufen soll. Ein Prozess muss auch nicht ganz auf einem Kern oder nur auf einem Kern laufen + Der Aufruf von `fork()` gibt im Elternprozess die Prozess-ID des Kindprozesses zurück, im Kindprozess hingegen den Wert 0. Ja, das steht auch so in der Man Page. Die Annahme ist hier, dass kein Fehler aufgetreten ist. - Threads, die mittels `pthread_create()` erzeugt wurden, besitzen jeweils einen eigenen Adressraum. Nein, Kind-Threads (im Kontext von der Pthread Bibliothek.) teilen den Addressraum mit dem Eltern-Thread. Prozesse haben eigene Addressräume. - Die Veränderung von Variablen und Datenstrukturen in einem mittels `fork()` erzeugten Kindprozess beeinflusst auch die Datenstrukturen im Elternprozess. Nein, allgemein nicht, außer der Benutzer richtet dieses spezifisch ein (Siehe `shm_open(3)`), was aber ohne weiteres nicht der Fall ist. . 0 Was ist ein Stack-Frame? (Februar 2023) - Der Speicherbereich, in dem der Programmcode einer Funktion abgelegt ist. Nein, ein Stack-Frame liegt im Stack Segment, und der Programmcode liegt im Text-Segment. - Ein Fehler, der bei unberechtigten Zugriffen auf den Stack-Speicher entsteht. Nein, es gibt keinen gesonderten Namen für Fehlerhaften Zugriff auf den Stack-Namen. + Ein Bereich des Speichers, in dem u.a. lokale automatic-Variablen einer Funktion abgelegt sind. Ja, ein Stack-Frame wird beim betreten einer Funktion angelegt für alle Metadaten und Daten welche zur ausführung benötigt werden und aufgeräumt sobald die Funktion verlassen wird. - Ein spezieller Registersatz des Prozessors zur Bearbeitung von Funktionen. Nein, es ist kein Registersatz. . 0 Welche der folgenden Informationen wird typischerweise in dem Seitendeskriptor einer Seite eines virtuellen Adressraums gehalten? - Die Zugriffsrechte auf die jeweilige Seite (z. B. lesen, schreiben, ausführen). Ja, so setzt das Betriebsystem bspw. um, dass ein Text Segment ausführbar aber nicht schreibbar ist. - Die Identifikation des Prozesses, dem die Seite zugeordnet ist. Nein, das Seiten existieren unabhängig von Prozessen und müssten per se nicht dafür benutzt werden, um logische Speicherräume auf Betriebsystemen mit unabhängigen Prozessen umzusetzen. - Die Zuordnung zu einem Segment (Text, Daten, ...). Nein, dieses wird muss man sich nicht in dem Seitendeskriptor merken, weil es nur wichtig ist, dass die Seite sich gemäß dem Verständniss von diesen Segmenten verhällt (lesbar, ausfübar, ...). - Die Position der Seite im virtuellen Adressraum. Nein, diese Zuordnung findet nicht im Seitendeskriptor statt, sondern im Betriebsystem. . 0 Beim Blockieren in einem Monitor muss der Monitor freigegeben werden. Warum? (2023-02) - Weil kritische Abschnitte immer nur kurz belegt sein dürfen. Für die Performanz eines Programms ist das sicher vorteilhaft, jedoch hat das nichts mit der Frage zu tun. - Weil sonst die Monitordaten inkonsistent sind. Nein, gegenseitiger Auschluss wäre sonst auch gegeben. + Weil ein anderer Thread die Blockierungsbedingung nur aufheben kann, wenn er den Monitor vorher betreten kann. Ja, vergleiche z. B. blockierende Warteschlange. Würde ein konsumierender Thread nicht den Monitor freigeben, so könnte kein produzierender Thread ein Element einfügen. - Weil der Thread sonst aktiv warten würde. Nein, der Thread wartet passiv auf den Monitor. . 0 Welche Aussage zu Prozessen und Threads ist richtig? (2023-02) - Mittels ~fork()~ erzeugte Kindprozesse können in einem Multiprozessor-System nur auf dem Prozessor ausgeführt werden, auf dem auch der Elternprozess ausgeführt wird. Nein, es spricht nichts dagegen, dass das Betriebssystem einen Prozess auf einem anderen Prozessor als dem urpsrünglichen einlastet. + Der Aufruf von ~fork()~ gibt im Elternprozess die Prozess-ID des Kindprozesses zurück, im Kindprozess hingegen den Wert 0. Ja, zumindest wenn kein Fehler aufgetreten ist. Siehe ~fork(2)~. - Threads die mittels ~pthread_create()~ erzeugt wurden, besitzen jeweils einen eigenen Adressraum. Nein. Prozesse besitzen einen eigenen Adressraum. Mehrere Threads in einem Prozess teilen sich einen Adressraum. - Die Veränderung von Variablen und Datenstrukturen in einem mittels ~fork()~ erzeugten Kindprozess beeinflusst auch die Datenstrukturen im Elternprozess. Nein. Der Kindprozess arbeitet auf einer Kopie des gesamten Adressraums. . 0 Welche Aussage zum Thema Synchronisation ist richtig? (2023-02) - Die V-Operation kann auf einem Semaphor nur von dem Thread aufgerufen werden, der zuvor auch die P-Operation aufgerufen hat. Nein, P und V können von beliebigen, auch unterschiedlichen, Threads aus aufgerufen werden. Vergleiche ~jbuffer~. + Durch den Einsatz von Semaphoren kann ein wechselseitiger Ausschluss erzielt werden. Ja, eine Semaphore mit initialem Wert von 1 implementiert *mutual exclusion*, wenn P und V immer paarweise nacheinander aufgerufen werden. - Ein Semaphor kann ausschließlich für mehrseitige Synchronisation (*multilateral synchronisation*) verwendet werden. Nein, das würde bedeuten, dass man damit nur Synchronisationsmechanismen implementieren kann, bei denen jeder Zugriff und nicht nur Entnahmezugriffe auf das Betriebsmittel dem wechselseitigen Ausschluss unterliegt. (vgl. [10.1 S.14]) Jedoch lässt sich z. B. eine blockierende Warteschlange mit nichtblockierender Entnahme implementieren, bei welcher die Semaphore nur Konsumenten bei einer leeren Warteschlange blockiert - Einseitige Synchronisation (*unilateral synchronisation*) erfordert immer Betriebssystemunterstützung. Nein, diese kann im *userspace* zum Beispiel durch atomare Variablen (hier also mit Unterstützung des Prozessors) realisiert werden. . 0 Welche der folgenden Aussagen zu statischem bzw. dynamischem Binden ist richtig? (2023-02) - Änderungen am Code einer dynamischen Bibliothek (z. B. Bugfixes) erfordern immer das erneute Binden aller Programme, die diese Bibliothek benutzen. Ja, zumindest in der Theorie müssen Programme, die eine dynamische Bibliothek einbinden nur neugestartet werden, nachdem diese ausgetauscht wurde nur neugestartet werden, wonach sie durch den dynamischen Binder neu gebunden werden. - Beim statischen Binden werden alle Adressen zum Ladezeitpunkt aufgelöst. Nein, das passiert hier bereits beim Binden. + Beim dynamischen Binden erfolgt die Adressauflösung beim Laden des Programms oder zur Laufzeit. Ja, beim Laden werden die Adressen der verwendeten Symbole durch den *dynamic linker* aufgelöst. Zur Laufzeit können jedoch noch Bibliotheken nachgeladen werden (~dlopen(3)~). - Statisch gebundene Programme können zum Ladezeitpunkt an beliebige virtuelle Speicheradressen platziert werden. Nein. Das kann, muss aber nicht so sein. Dynamische Bibliotheken müssen hingegen *position-independent-code* enthalten, um in den Adressbereich des Zielprogramms geladen werden zu können. .