Rush

Sofortiges Aufsammeln von Zombieprozessen

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.

Rush
Ich bin nicht sicher, ob ich [m]sigsuspend [/m]richtig verstehe. Bereits eingebaut habe ich eine Signalbehandlung für SIGCHLD, welche die Zombieprozesse sofort aufsammelt.

So wie ich es verstehe, nimmt sigsuspend eine Maske, und wartet solange, bis eines der in der Maske angegebenen Signale auftaucht.

  1. Läuft das Programm danach normal weiter (von SIGKILL und SIGSTOP abgesehen)?
  2. Wo bringt man sigsuspend an? Steht es nach dem fork im Vater könnte das Kind ja bereits terminiert sein. Steht es vor dem fork, ist das Kind noch gar nicht erzeugt.

Ich habe es so verstanden, dass sigsuspend so lange blockiert, bis eines der nicht in der Maske angegebenen Signale auftaucht - und dann quasi einfach zurückkehrt und das Programm weiterläuft.
(Zumindest funktioniert es bei mir, wenn ich es in dieser Hinsicht an der von dir angedeuteten Stelle verwende.)
Aber die Synchronisation dazu (dein 2.) würde mich an dieser Stelle auch mal interessieren.

Was ich auch noch feststellen konnte:
Wenn ich die Rush mit Strg+Z im Terminal anhalte (das müsste äquivalent zu dem Senden eines SIGTSTP-Signals an die Rush sein), dann kann ich dieses Signal ja nicht blockieren (weil man STOP-Signale nicht blockieren kann).
Zumindest habe ich eine Maske, die alle Signale bis auf SIGCHLD enthält, an sigsuspend übergeben - und sigsuspend kommt trotzdem zurück, wenn der User Strg+Z eingibt.
Ich dachte eigentlich, dass man nur SIGSTOP nicht blockieren kann, SIGTSTP aber schon. Aber wie oben beschrieben - sigsuspend kommt zurück trotz der Maske.
Das hat aber den Nachteil zur Folge, dass damit die Rush schon wieder in den nächsten „Befehlseingabe-Zyklus“ kommt, obwohl der Vordergrundprozess noch am Laufen ist.
Kann ich das irgendwie verhindern oder liegt das einfach an einem von mir gemachten Fehler, den ich übersehe?
Ich hatte überlegt, das sigsuspend einfach in eine Endlosschleife zu packen, die erst aufhört, wenn ein Flag gesetzt wird.
Das Flag wird dabei im SIGCHLD-Handler gesetzt, sobald ein Vordergrundprozess-Zombie aufgeräumt wird und zurückgesetzt, sobald ein neuer Vordergrundprozess gestartet werden soll.
Doch auch hier bin ich mir wieder nicht sicher, ob das Synchronisations-technisch ohne Zusatzmittel überhaupt funktioniert. (Vielleicht sollte man die Variable noch als volatile deklarieren? Doch selbst das behebt ja keine Sichtbarkeitsprobleme.)


So habe ich es mittlerweile auch in den Übungsfolien gefunden.

Muss man dafür so alle Signale, die es gibt, in ein Set hinzufügen und blockieren und nach sleep die alte Maske wiederherstellen?


Gratulation, du hast einen der Fallstricke in dieser Aufgabe erfolgreich erkannt. Mit etwas nachdenken kommst du bestimmt auch darauf, welche Signale du an welchen Stellen blockieren musst, um dieses Problem zu umgehen. Nachdem das der Lerninhalt dieser Aufgabe ist möchte ich dir die Lösung nur ungern auf dem Silbertablett servieren :wink:

[quote=ceptoplex]Ich hatte überlegt, das sigsuspend einfach in eine Endlosschleife zu packen, die erst aufhört, wenn ein Flag gesetzt wird.
Das Flag wird dabei im SIGCHLD-Handler gesetzt, sobald ein Vordergrundprozess-Zombie aufgeräumt wird und zurückgesetzt, sobald ein neuer Vordergrundprozess gestartet werden soll.[/quote]
Das klingt schon mal recht gut.

[quote=ceptoplex]Doch auch hier bin ich mir wieder nicht sicher, ob das Synchronisations-technisch ohne Zusatzmittel überhaupt funktioniert. (Vielleicht sollte man die Variable noch als volatile deklarieren? Doch selbst das behebt ja keine Sichtbarkeitsprobleme.)[/quote][m]volatile[/m] wäre an einer solchen Stelle definitiv notwendig, wenn du mit Optimierungen kompilierst. Welche Sichtbarkeitsprobleme bestehen denn deiner Meinung nach selbst mit [m]volatile[/m] noch? Denk daran: C ist nicht Java – eine als [m]volatile[/m] markierte Variable wird immer direkt in den Speicher geschrieben und von dort gelesen. CPU-Caches kannst du dabei ignorieren, weil sich die CPU selbst um deren Konsistenz kümmert.


Ja. Zuerst wird die Signalbehandlung des Signals ausgeführt (falls vorhanden), dann kehrt das [m]sigsuspend(2)[/m] ganz normal zurück.

Schau dir mal die Übungsfolien an … [m]sigsuspend(2)[/m] wird ja nie alleine verwendet, davor muss schon was passiert sein …

Richtig. Zum Füllen gibt es [m]sigfillset(3)[/m], zum Wiederherstellen ist der dritte Parameter von [m]sigprocmask(2)[/m] ganz praktisch.

Da wird ein [m]SIGTSTP[/m] geschickt, kein [m]SIGSTOP[/m]. Das kannst du also schon blockieren/abfangen.

Du hast keine Signalbehandlung für [m]SIGTSTP[/m].

Hast du dir mal überlegt was passiert, wenn ein [m]SIGCHLD[/m] für einen Hintergrundprozess auftritt, während ein Vordergrundprozess läuft?

1 Like

Ich steh noch auf dem Schlauch. Wird ein Vordergrundprozess gestartet, dann wird irgendwann der Signalhandler nach Terminieren dieses Prozesses aufgerufen. In der Zwischenzeit könnte aber auch ein anderer Hintergrundprozess terminiert sein. Wie kann der Signalhandler unterscheiden, ob es sich um einen Vorder- oder Hintergrundprozess handelt?
Zuerst dachte ich, man könne nachschauen, ob die pid in der plist vorkommt. Aber was ist, wenn ein SIGCHLD von „außen“ reinkommt? Daher kann man aus dem Fehlen der pid in der plist nicht schließen, dass es sich um einen Vordergrundprozess handelt…


Wieso?
Ein Prozess erhält doch nur [m]SIGCHLD [/m](„SIGNAL CHILD“) für die Prozesse, die er selbst durch fork() verursacht hat und deren Parent er ist.

Danke an die anderen, das hat mir auf jeden Fall geholfen.

Jetzt schon. :smiley:


Richtig. Du musst dem Signalhandler sagen, was ein Vordergrund- und was ein Hintergrundprozess ist (Tipp: es gibt immer nur einen Vordergrundprozess).

Das würde nicht helfen, weil auch Vordergrundprozesse in der plist stehen. Aber du kannst dem Signalhandler ja leicht mitteilen, was ein Vordergrundprozesse ist, denn dessen [m]pid[/m] kennst du ja …

:wink:


Wieso? Man kann es doch auch so implementieren, dass Vordergrundprozesse nicht in der plist stehen und sich durch diesen Umstand erkennen lassen.
Oder war meine Aussage, dass SIGCHLDs nur für eigens gefork()te Kinder erhalten werden, falsch?

Jetzt muss ich aber doch nochmal nerven.
Das einzige, was mich jetzt nämlich immer noch stört, ist immer noch im Bezug auf BTLs originales Problem der Synchronisation.
Wenn ich mir jetzt merke, ob wirklich noch ein Vordergrund Prozess läuft, dann müssen doch eigentlich die Schritte „Überprüfung des Gemerkten → sigsuspend() aufrufen“ atomar passieren.
Denn wenn das Child bspw. zwischen - also nach der Überprüfung und vor dem Setzen der Maske/Blockieren mit sigsuspend - vom Signal-Handler aufgeräumt wird, hab ich ja eine fälschliche Blockierung der Rush.

EDIT: Ich glaube in der Übungsfolie wird mir jetzt der Lösungsansatz klar. :slight_smile:


(weit) VOR der schleife SIGCHILD blockieren, dann irgendwas tun und dann in einer while-schleife sigsuspend machen.

sigsuspend macht atomar folgendes (wenn es das richtige set übergeben bekommt):
unblock schlafen block

Also ist das SIGCHLD noch vor der whileschleife blockiert, dann kommt atomar im schleifenrumpf: unblock SIGCHLD, schlafen. Wenn jetzt ein SIGCHLD kommt wacht er auf und blockiert (immernoch atomar) wieder SIGCHLD. Jetzt wird überprüft ob sich was an der Schleifenbedingung geändert hat. Wenn diese weiterhin true ist, dann kommt wieder ein sigsuspend und wir schlafen weiter bis er endlich ein false in der Schleifenbedingung bekommt und er aus der schleife rausspringt.

SIGCHLD blockieren;

while(bedingung){
   sigsuspend(amazing_set);
}

edith hofft, dass ich das so richtig verstanden habe… :smiley:


@ arox: Danke.
Ich hab mich zu sehr auf meine Variable eingeschossen, dass ich vergessen hatte, dass ich die Signalbehandlung ja auch unterbrechen kann. :slight_smile:


Macht irgendwie Sinn :wink: Ich hatte mir vorgestellt, da sitzt einer vor htop und stellt dem Prozess ein SIGCHLD nach dem anderen zu. Aber da hängt’s an waitpid.

Womit ich wieder bei meiner ersten Frage bin: Was passiert, wenn während des Irgendwas-Tuens ein Hintergrundprozess terminiert? Wird das SIGCHLD dann aufgehoben, bis das Programm es wieder annimmt oder einfach weggeworfen?

SIGCHLD blockieren;
  -  HINTERGRUNDPROZESS TERMINIERT  -
while(bedingung){
   sigsuspend(amazing_set);
}

nein, nur die zustellung des signals wird verzögert.

und denk dran du musst auf jeden Fall verhindern, dass dein vater nicht mitkriegt, dass das kind gestorben ist…


Könnte man, aber dann muss man die Ausgabe des Existstatus und Co. nochmal implementieren.

Nein, das stimmt. Ist aber auch egal, weil du ja „falsche“ PIDs eh einfach ignorierst.

:slight_smile:

Du meinst das Richtige, aber der korrekte Begriff ist verzögern, nicht unterbrechen.


Ob das atomar passiert oder nicht, ist egal. Nur das deblockieren und schlafen muss atomar sein.


Wenn das einer macht, dann liefert [m]waitpid(2)[/m] einen Fehler zurück, den man in dieser Aufgabe am besten ignoriert (oder [m]abort(2)[/m]et).


Danke an alle, jetzt sind mir die Fragen für heute ausgegangen :slight_smile:

1 Like

Wieso wird hier SP eigentlich immer erst dann diskutiert, wenn ich bereits abgeben musste? ^^


Mach doch selbst einen auf. :stuck_out_tongue:
Nein … ich weiß schon was du meinst.
Manchmal stößt man bei sich erst auf Fehler, weil man die Gedankengänge anderer versucht nachzuvollziehen.