TProcess erzeugt Zombies - wie verhindere ich das?

Rund um die LCL und andere Komponenten
Antworten
Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

TProcess erzeugt Zombies - wie verhindere ich das?

Beitrag von Timm Thaler »

Ok, ich bin ja selber schuld:

Code: Alles auswählen

    try
      phnd := TProcess.Create(nil);
      phnd.CommandLine := sndplayer + sound;
      phnd.Options := [];
      phnd.Execute;
    finally
      phnd.Free;
    end;


Ich starte unter Linux (Raspbian) den omxplayer und übergebe ein Soundfile, welches abgespielt wird. Das Programm darf nicht auf das Ende des Abspielens warten und eigentlich interessiert das Programm sich nicht für den Erfolg des Abspielens.

Nun erzeugt mir das leider jedesmal einen Zombieprozess (<defunct>), und die sammeln sich an. Da mein Programm dauerhaft läuft, werden dessen Childs, sprich die Zombies auch nicht gelöscht.

Nun habe ich zu den Zombies die Info gefunden "Der Linux-Kernel bietet für Prozesse, die nicht am Status ihrer Kinder interessiert sind, eine einfache – wohlgemerkt nicht standardisierte – Methode, Zombies loszuwerden: Gibt ein Prozess explizit an, dass er SIGCHLD ignorieren will (im Gegensatz zum Ignorieren per Default, wenn kein Handler angegeben ist), so löscht Linux die Zombies automatisch, ohne auf eine Statusabfrage zu warten." https://de.wikipedia.org/wiki/Zombie-Prozess#Besonderheit_im_Linux-Kernel

Sowas hätte ich gern, allerdings finde ich unter https://www.freepascal.org/docs-html/fcl/process/tprocess.options.html nichts dazu.

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: TProcess erzeugt Zombies - wie verhindere ich das?

Beitrag von mse »

Timm Thaler hat geschrieben:Nun habe ich zu den Zombies die Info gefunden "Der Linux-Kernel bietet für Prozesse, die nicht am Status ihrer Kinder interessiert sind, eine einfache – wohlgemerkt nicht standardisierte – Methode, Zombies loszuwerden: Gibt ein Prozess explizit an, dass er SIGCHLD ignorieren will (im Gegensatz zum Ignorieren per Default, wenn kein Handler angegeben ist), so löscht Linux die Zombies automatisch, ohne auf eine Statusabfrage zu warten."

SIG_IGN wird mit der libc funktion sigaction() gesetzt.
https://linux.die.net/man/2/sigaction
https://linux.die.net/man/3/sigaction
FPC hat vermutlich fpsigaction() als Ersatz, Marco kann da sicher mehr dazu sagen.
In MSEgui gibt es für den Zweck ein minimal libc Interface für alle unterstützten Unix Platformen.
SIG_IGN für SIGCHLD zu setzen verhindert, dass das Programm auf die Terminierung von Kindprozessen reagieren kann, vermutlich ist das nicht empfehlenswert.
Die Zombies enstehen wahrscheinlich darum, weil die TProcess Instanzen vor der Beedigung des Prozesses zerstört werden und kein Aufruf von waitpid() erfolgt.
https://linux.die.net/man/2/waitpid
Vermutlich ist es besser durch Abfrage der entsprechenden TProcess Property waitpid() aufzurufen und die Beendigung des Prozesses abzuwarten und erst dann TProcess zu zerstören.
Gibt es nicht eine Lazarus Prozess-Komponente mit erweiterten Möglichkeiten?
MSEgui hat eine automatische "Zombie-Überwachung" in lib/common/kernel/linux/mseprocmonitor.pas. Da die MSEgui tmseprocess Komponente damit zusammenarbeitet, kann der procmonitor vermutlich nicht 1:1 in Lazarus übernommen werden.

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: TProcess erzeugt Zombies - wie verhindere ich das?

Beitrag von Timm Thaler »

mse hat geschrieben:Vermutlich ist es besser durch Abfrage der entsprechenden TProcess Property waitpid() aufzurufen und die Beendigung des Prozesses abzuwarten und erst dann TProcess zu zerstören.


Das habe ich mir auch schon so gedacht, würde es aber gern vermeiden. Das Programm sampelt auf dem Raspi verschiedene GPIOs mit 25msec, legt darüber eine Entprellroutine, und wenn ein Ereignis eintritt, wird ein Soundfile abgespielt (omxplayer) oder eine Message (curl => telegram) gesendet.

1. Das Programm hat keine Möglichkeit, auf ein Versagen des Childs zu reagieren, wird der Sound nicht abgespielt oder die Message nicht gesendet => Pech.
2. Das Programm darf auch nicht auf das Ende des Childs warten, weil es weiter GPIOs sampeln muss.
3. Das Programm muss mehrere Ereignisse parallel verarbeiten können. Mehrere omxplayer gleichzeitig sind kein Problem, getestet.

Daraus folgt, wenn ich das Beendigen des Prozesses abwarten will, muss ich eine dynamische Liste der Prozesse führen und die regelmäßig abarbeiten, obwohl ich sie eigentlich nicht brauche. Das wollte ich möglichst vermeiden.

Ich probiere mal, ob ich mit SIG_IGN was erreichen kann...

Warf
Beiträge: 1910
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: TProcess erzeugt Zombies - wie verhindere ich das?

Beitrag von Warf »

Es gibt auch ein nicht blockierenden call von waitpid (mit nohang als Argument) schau dir einfach mal die man Page an. Einfach Öle paar Zyklen einen call machen und falls ein Prozess terminiert hat sollte der Zombie gelöscht werden, falls nicht blockiert dein Prozess aber dennoch nicht

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: TProcess erzeugt Zombies - wie verhindere ich das?

Beitrag von Socke »

Eine weitere Alternative wäre es, jeden Prozess blockierend in einem eigenen Thread zu starten. Der Thread kann mit FreeOnTerminate so eingestellt werden, dass er nach Ende automatisch freigegeben wird.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: TProcess erzeugt Zombies - wie verhindere ich das?

Beitrag von mse »

In Lazarus lcl/interfaces/gtk2/gtk2widgetset.inc findet sich

Code: Alles auswählen

 
procedure TGtk2WidgetSet.ProcessChildSignal;
var
  pid: tpid;
  reason: TChildExitReason;
  status: integer;
  info: dword;
  handler: PChildSignalEventHandler;
begin
  repeat
    status:=0;
    pid := fpwaitpid(-1, status, WNOHANG); <<<<<------
    if pid <= 0 then break;
    if wifexited(status) then
    begin
      reason := cerExit;
      info := wexitstatus(status);
    end else
 

Wird die Prozedur nicht aufgerufen?

Antworten