Disclaimer: Dieser Thread wurde aus dem alten Forum importiert. Daher werden eventuell nicht alle Formatierungen richtig angezeigt. Der ursprüngliche Thread beginnt im zweiten Post dieses Threads.
4 ist falsch, [m]exit(2)[/m] überführt den Prozess in den Zustand beendet. 1 ist richtig, ein Prozess kann sich nur selbst blockieren (z.B. durch Disk-I/O, Zugriff auf ausgelagerten Speicher (Pagefault), etc.).
4 ist falsch. Für den Scheduler ist es nicht intransparent, der kann ja den Prozess beliebig schedulen ohne dass eine Prioritätsverletzung auftritt. 1 ist richtig, CAS geht nicht in C99 (wird haben ja das GCC-Builtin benötigt).
2 stimmt, nur die Rechte des Verzeichnis sind relevant um eine Datei zu löschen.
3 ist falsch, sobald die Datei weg ist, kannst du keinen Hardlink mehr anlegen (denn dann war der Hardlink-Count ja schon 0 und das Dateisystem hat die Inode inklusive Dateiinhalt entfernt).
6 stimmt auch. „foo“ und „bar/foo“ (zweimal Dateiname „foo“) ist natürlich möglich.
2 stimmt auch, z.B. beim Schreiben in eine read-only Seite gibt es trotzdem einen Page-Fault.
6 stimmt nicht: ab | cd (wobei ab und cd Buddies sind), b und c kannst du jedoch nicht verschmelzen.
Bitte korrigiere deine Lösungen, damit zukünftige Leser des Threads es einfacher haben.
Vielen Dank kronos für deine Lösung zur tesa
Kannst du mir erklären, warum bei [m]kill(0, SIGTERM)[/m] bzw. [m]kill(0, SIGKILL)[/m] genau alle Kinder sterben? Das Hauptprogramm soll ja weiterlaufen.
Ich hab’s mir versucht so zu erklären, dass bei fork() 0 als pid für das Kind zurückgegeben wird. Hat das was damit zu tun?
Die runTestsuite-Methode sollte man am Ende um ein printSummary ergänzen oder?
Allgemeine Frage: Ist es richtig, dass wenn man eine Signalbehandlungsfunktion besipielsweise für SIGALRM setzt und dann fork() aufruft, sowohl Vater als auch Kind zur Signalbehandlung kommen könnten, jedoch letztendlich nur der schnellere es tut?
Beispiel:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
static void die(const char* message) {
perror(message);
exit(EXIT_FAILURE);
}
static void sigAlrmHandler(int signum) {
printf("Alarm was received by %d\n", getpid());
}
static void sigChldHandler(int signum) {
printf("Child died.\n");
}
int main(int argc, char* argv[]) {
// Apply signal handling
struct sigaction action;
if(-1 == sigemptyset(&action.sa_mask))
die("sigemptyset");
action.sa_flags = SA_RESTART;
action.sa_handler = sigAlrmHandler;
if (-1 == sigaction(SIGALRM, &action, NULL))
die("sigaction");
struct sigaction childHandler;
if(-1 == sigemptyset(&childHandler.sa_mask))
die("sigemptyset");
childHandler.sa_flags = SA_RESTART | SA_NOCLDSTOP | SA_NOCLDWAIT;
childHandler.sa_handler = sigChldHandler;
if (-1 == sigaction(SIGCHLD, &childHandler, NULL))
die("sigaction");
pid_t pid = fork();
switch(pid) {
case -1:
die("fork");
case 0:
sleep(1);
sleep(1);
break;
default:
alarm(1);
printf("Parent called alarm(1). Child's id is %d\n", pid);
printf("Wait until the child has died and then press enter to leave...\n");
char c = getchar();
break;
}
return EXIT_SUCCESS;
}
Als Output habe ich bisher immer bekommen, dass der Vater die Signalbehandlung durchlaufen hat. Das Kind nie, obwohl es zu dem Zeitpunkt noch lebt.
Nein, hat nichts damit zu tun. Zitat aus [m]man 2 kill[/m]:
In [m]man 2 fork[/m] steht allerdings:
Ich vermute also, dass das so nicht funktioniert, sondern einfach der Prozess stirbt, den das Signal erreicht. (Was immer der Vater sein sollte, da die Kinder ja andere PGIDs haben.)
Alles ohne Gewähr. Ich hab’s nur schnell nachgeschaut und das klingt relativ logisch für mich.
„process group“ != „process ID“. Prozessgruppen sind etwas anderes, für diese Konzepte fehlt aber in SP die Zeit. [m]man setpgid[/m] und [m]man tcsetpgrp[/m] für mehr Informationen. Prozessgruppen erlauben es (unter anderem) mehrere Prozesse zusammenzufassen und Signale an alle Prozesse innerhalb eine Gruppe zu schicken. Das ist z.B. für Pipes („grep foo | sort | tail“) praktisch. Man will ja alle Prozesse beenden, wenn man Ctrl-C drückt. Auch für Hintergrund-Prozess ist das wichtig.
Nein. Nur der Prozess, der das [m]alarm()[/m] aufruft, bekommt das [m]SIGALRM[/m].
Du brauchst keine Fehlerbehandlung für [m]sigemptyset(3)[/m]. Bei [m]sigaction(3)[/m], brauchst du ebenfalls keine, wenn die Parameter fest sind (wie hier).
Nein, die Sache mit den Prozessgruppen funktioniert nochmal ein bisschen anders.
Was bei dieser Aufgabe gedacht ist: Iteriere über das Array von Testfall-Strukturen, das zu der Testsuite gehört, und sende an jede der gespeicherten PIDs das Signal (sofern dieser Testfall nicht schon terminiert ist).
Das kannst du auch leicht selbst nachschauen: [m]ls -lai / | head[/m] und [m]ls -lai /etc | head[/m], unter der Annahme, dass [m]/etc[/m] im selben Dateisystem wie [m]/[/m] ist ([m]-i[/m] zeigt die Inode an).
Zur Aufgabe 4:
Wir haben fuer 4 a und 4 b eine Loesung zusammengestellt, wissen aber nicht wie wir bei der 4 c herangehen sollen.
Unsere Antwort:
Auswirkung des Verfahrens auf nur einen Prozess (einseitige S.) oder mehrere Prozesse (mehrseitige S.)
Reihenfolge der Prozesse ist klar (einseitige S.) oder unvorhersehbar (mehrseitige S.)
Unsere Antwort:
Wiederverwendbare Betriebsmittel: Betriebsmittel, die von mehreren Prozessen genutzt werden koennen und dabei nicht aufgebraucht werden. Diese BM koennen nur begrenzt erstellt werden. Eine weitere Unterteilung dieser BM ist in {un,}teilbare BM.
CPU (HW)
Peripherie-Geraete (HW)
Speicher (HW)
Dateien (SW)
I/O-Buffer (SW)
Seitenrahmen (SW)
Deskriptoren (SW)
…
Konsumierbare Betriebsmittel: Betriebsmittel, die nur von einem Prozess genutzt werden koennen und dabei aufgebraucht werden. Diese BM koennen unendlich oft produziert werden.
Signale (HW)
Nachrichten (SW)
Signale (SW)
Bei der 4c ist unklar, was denn ein Zugriffsmuster ist. Ist dies nur die Reihenfolge von V/P Aktionen?
Und einseitige/mehrseitige Synchronisation wird ja dann wird ja anhand der Kategorie des Betriebsmittels festgestellt, ist also eine quasi Wiederholung der Frage in 4b?
Hat da jemand was dazu bzw. kann einen Tipp/eine Loesung vorschlagen?
Ich hätte hier noch erwähnt, dass bei einseitiger Synchronisation eine binäre Semaphore benötigt wird und bei mehrseitiger eine zählende Semaphore.
Ich bin mir auch nicht ganz sicher, ob deine Antworten:
Reihenfolge ist klar und
Auswirkungen nur auf einen Prozess/mehrere Prozesse
stimmen.
Wenn ich das richtig kapiert habe, dann geht es bei einseitiger Synchro doch darum, dass ein Thread/Prozess quasi „durchläuft“ und andere sich daran synchronisieren müssen.
Und bei mehrseitiger dann eben darum, dass es einen kritischen Abschnitt zu schützen gilt.
Ich bin mir aber wie gesagt selbst nicht ganz sicher, daher bitte Korrekturen / Bestätigungen
Danke!