Skip to content
Snippets Groups Projects
Verified Commit 7de7f9e0 authored by Maximilian's avatar Maximilian :notebook_with_decorative_cover:
Browse files

More questions and gen.pl extensions

parent c6d1b6e1
No related branches found
No related tags found
No related merge requests found
......@@ -9,7 +9,8 @@ use IPC::Open2;
use Digest::MD5 qw(md5_base64);
my @hlwords = qw/immer nie jede jedem jedes muss keine alle nicht/;
my @markdown = qw/pandoc -f markdown+smart --html-q-tags --ascii/;
my @markdown = qw/pandoc -f markdown+smart+fenced_code_blocks+backtick_code_blocks --html-q-tags --ascii/;
# my @markdown = qw/cat/;
my $question;
my $single_choice;
......@@ -99,11 +100,11 @@ while (<>) {
$question =~ s/\Q($source)\E//;
chomp $source;
}
} elsif (/^[|](.+)/) {
} elsif (/^[|](.*)/) {
if ($last_option{"option"}) {
$last_option{"option"} .= $1;
$last_option{"option"} .= "$1\n";
} else {
$question .= $1;
$question .= "$1\n";
}
} elsif (/^@(.*)/) {
$media = $1;
......
......@@ -118,11 +118,61 @@ Nein. Hier sind beide falsch.
- Seitennummer 0x2, Offset 0x8
Nein. Hier ist der Offset offensichtlich falsch.
- Seitennummer 0x8, Offset 0x2
Nein. Da hier der Offset 10 Bit und kein Vielfaches von 4 hat, darf man nicht einfach die Hexadezimaldarstellung an der Grenze eines *nibbles* (= Halbbyte, 4 Bit, ein Zeichen in Hexadezimaldarsetllung) zerlegen.
Nein. Da hier der Offset 10 Bit und kein Vielfaches von 4 hat, darf man nicht einfach die Hexadezimaldarstellung an der Grenze eines *nibbles* (= Halbbyte, 4 Bit, ein Zeichen in Hexadezimaldarsetllung) zerlegen. Deswegen ist hier die Seitennummer falsch.
.
0 Welche Aussage zu UNIX/Linux-Dateideskriptoren ist korrekt?
+
-
+ Nach dem Aufruf von fork(2) teilen sich Eltern und Kindprozess die den gemeinsamen Dateideskriptoren zu Grunde liegenden Kernel-Datenstrukturen.
Ja, vergleiche zum Beispiel `sister`, bei der ein Kindprozess für die Bearbeitung einer Anfrage zuständig war und den Dateideskriptor verwendet, der im Elternprozess von `accept(3)` zurückgegeben wurde.
- Da Dateideskriptoren Zeiger auf Betriebssystem-Interne Strukturen sind, können diese zwischen Prozessen geteilt werden.
Der Dateideskriptor ist lediglich ein Index in die Dateideskriptortabelle pro Prozess im *kernel space*. Da diese nicht geteilt ist, ist auch das Teilen von Dateideskriptoren im Allgemeinen nicht zielführend.
- Der Dateideskriptor enthält die nötigen Metadaten einer Datei und ist auf der Festplatte gespeichert.
-
Nein, das wäre die `inode`. Der Dateideskriptor ist eine Referenz (jedoch kein Pointer) auf eine Datenstruktur im Betriebssystem, die u. a. auch die Position des Prozesses in der Datei enthält.
- Das Flag `FD_CLOFORK` eines Dateideskriptors sorgt dafür, dass der Dateideskriptor bei einem Aufruf von `fork(2)` automatisch geschlossen wird.
Nein, dieses Flag existiert nicht. Angespielt wird hier auf `FD_CLOEXEC`, was die beschriebene Wirkung bei einem Aufruf von `exec(3)` zeigt.
.
0 Welche Aussage über die Koordinierung von kritischen Abschnitten unter Unix ist richtig?
+ Für die Synchronisation zwischen dem Hauptprogramm und einer Signalbehandlungsfunktion sind Schlossvariablen (Locks) ungeeignet.
Ja. Signalbehandlung stellt asymmetrische Nebenläufigkeit dar. Der aktuelle Ausführungsstrang wird also unterbrochen, um zum *signal handler* zu springen. Wenn dieser nun versucht, ein *lock* zu sperren, das schon vom Hauptprogramm gesperrt wurde, so wartet dieser auf das Hauptprogramm, welches jedoch durch die Signalbehandlung unterbrochen ist. Es kommt zu einer Verklemmung (*deadlock*).
- Ein Unix-Prozess kann durch das Sperren von Unterbrechungen (Interrupts) den Speicherzugriff in einem kritische Abschnitte [sic!] synchronisieren.
Nein. Einerseits ist das Sperren von Interrupts, die ja nicht notwendigerweise im Zusammenhang mit dem Prozess stehen müssen, eine privilegierte Operation, die dem Betriebssystem vorenthalten ist. Andererseits würde dies bei manchen Formen von Nebenläufigkeit nicht den gewünschten Effekt erzielen, da z. B. auf einem Multiprozessorsystem mehrere leichtgewichtige Prozesse (*kernel-level threads*) echt nebenläufig Speicherzugriffe durchführen können, ohne dass einer der Prozesse durch einen Interrupt verdrängt wird.
- In einem Unix-Prozess kann es keinen kritischen Abschnitt geben, da immer nur ein Aktivitätsträger pro Prozess aktiv ist.
Nein. Die Ressourcen eines schwergewichtigen Prozesses können zwischen verschiedenen leichtgewichtigen Prozessen geteilt sein, die nebenläufig einen Aktivitätsstrang ausführen.
- Kritische Abschnitte können unter Unix nur mit Semaphoren synchronisiert werden.
Nein. es gibt vielerlei Synchronisationsmechanismen für verschiedene Arten von Nebenläufigkeit, für kritische Abschnitte kann insbesondere auch `pthread_mutex` verwendet werden.
.
1 Welche der Aussagen zum folgenden Programmfragment sind richtig?
|
|
|~~~~~
|static int a = 2022;
|void f1 (const int *y) {
| static int b;
| int c;
| char *d = malloc(0x802);
| void (*e)(const int *) = f1;
| y++;
| //...
|}
|~~~~~
|
+ `e` liegt im Stacksegment und zeigt in das Textsegment.
Ja. `e` ist ein Zeiger auf die Funktion `f1`. Funktionen liegen im Textsegment. Zudem ist `e` eine lokale Variable, liegt also im Stacksegment.
- `c` ist mit dem Wert 0 initialisiert.
Nein, denn nur globale Variablen werden mit 0 initialisiert, wenn sie nicht anderweitig initialisiert werden. `c` ist uninitialisiert.
- Die Anweisung `y++` führt zu einem Laufzeitfehler, da `y` konstant ist.
Ja. Das Ziel von `y` ist hier `const`, `y` selbst jedoch nicht. Pointerarithmetik auf `y` ist also erlaubt. Eine Merkregel hierfür lautet "`const` bezieht sich auf das Schlüsselwort links davon, außer es steht ganz links. Dann bezieht sich `const` auf das Schlüsselwort rechts davon." Hier bezöge sich const also auf `int`, nicht auf `*`.
+ `d` ist ein Zeiger, der in den Heap zeigt.
Ja. Mit `malloc(3)` wird Heapspeicher allokiert.
+ `a` liegt im Datensegment.
Ja. `a` ist eine globale Variable. Globale Variablen liegen im Datensegment. `a` liegt im Datensegment.
? `y` liegt im Stacksegment.
Gemäß der x86_64-POSIX-ABI liegen Funktionsparameter wie `y` in einem Register, das ist jedoch nicht plattformunabhängig garantiert. Ich vermute trotzdem, die erwartete Antwort hier ist "ja".
- `b` liegt im Stacksegment.
Durch die Verwendung von `static` innerhalb einer Funktion erzeugt man eine Variable, die zwar nur in diesem Gültigkeitsbereich sichtbar ist, jedoch die Semantik einer globalen Variable besitzt. Demnach liegt `b` im Datensegment.
- Die Speicherstelle, auf die `d` zeigt, verliert beim Rücksprung aus der Funktion `f1()` ihre Gültigkeit.
Nein, da diese Speicherstelle im Heap liegt und - im Gegensatz zu Stackspeicher - erst durch den Aufruf von `free(3)` ungültig wird.
.
......@@ -51,21 +51,22 @@
Nein, ein Zeiger wird immer noch als Wert an eine Funktion übergeben, d. h. es wird eine Kopie des Zeigers in das entsprechende Register
oder auf den Stack abgelegt. Das ein Zeiger eine Referenz auf eine Speicherstelle *ist*, spielt hierbei keine Rolle.
Beispiel: Würde die Aussage stimmen, so würde das folgende Programm "10" ausgeben. Es gibt jedoch "5" aus.
```c
#include <stdio.h>
static int b = 10;
static void pointers_are_values_too(int* arg) {
arg = &b; // arg zeigt hier auf b, ptr in main bleibt aber unverändert.
}
~~~
#include <stdio.h>
static int b = 10;
int main(void) {
int a = 5;
int* ptr = &a; // ptr zeigt auf a.
pointers_are_values_too(ptr);
printf("%d\n", *ptr); // ptr zeigt immer noch auf a.
}
```
static void pointers_are_values_too(int* arg) {
arg = &b; // arg zeigt hier auf b, ptr in main bleibt aber unverändert.
}
int main(void) {
int a = 5;
int* ptr = &a; // ptr zeigt auf a.
pointers_are_values_too(ptr);
printf("%d\n", *ptr); // ptr zeigt immer noch auf a.
}
~~~
.
0 Welche Aussage zu Programmbibliotheken ist richtig? (2020-02)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment