/bin/ps -A zeigt bereits beendete Programme an. Warum?

Antworten
Epcop
Beiträge: 159
Registriert: Di 29. Mai 2012, 09:36

/bin/ps -A zeigt bereits beendete Programme an. Warum?

Beitrag von Epcop »

Debian, Lazarus 4.0RC1


Hallo!

Mein Hauptprogramm startet ein externes Programm mit TProcess.
Mein Hauptprogramm prüft, mithilfe von ps -A, ob das extern gestartete Programm noch läuft. (Wichtig ist eigentlich nur, die Ausgabe von ps -A)

Soweit funktioniert alles.

Der Benutzer beendet nun das extern gestartete Programm.
ps -A, zeigt das extern gestartete Programm aber nun weiterhin an, obwohl es beendet wurde.

Nun wird es noch komischer. Ich habe viel herumprobiert. Starte ich über das Hauptprogramm das externe Programm mehrmals, zeigt das ps -A auch an. Beende ich als Benutzer alle externen Programme, zeigt ps -A trotzdem alle an. Wiederhole ich das, zeigt ps -A immer mehr externe Programme an, wird aber niemals weniger.

Ich würde erwarten, wenn der Benutzer das extern gestartete Programm beendet, verschwindet auch der Programmname in ps -A. Dem ist aber nicht so.

Das externe Programm wird erst dann nicht mehr angezeigt, wenn ich das Hauptprogramm beende.
Warum?

Liebe Grüße
Epcop

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2805
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: /bin/ps -A zeigt bereits beendete Programme an. Warum?

Beitrag von m.fuchs »

Kannst du mal deinen Quellcode zeigen, ein schneller Test bei mir(Lazarus 3.2, Linux Mint) war so wie du das erwartet hast.

Code: Alles auswählen

program ProcessTest;
{$MODE ObjFpc}
{$H+}

uses
  Classes, SysUtils, Process;

var
  p: TProcess;

begin
  p := TProcess.Create(nil);
  p.Executable := 'xed';
  p.Options := p.Options + [poWaitOnExit];
  p.Execute;
  WriteLn('Waiting...');
  ReadLn;
  p.Free;
  WriteLn('Bye...');
end.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1639
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: /bin/ps -A zeigt bereits beendete Programme an. Warum?

Beitrag von fliegermichl »

Wenn ein Programm andere Programme startet, so verbleiben diese als Zombies in der Prozessliste, bis der exit Status des Childprozesses abgefragt wurde.

Benutzeravatar
theo
Beiträge: 10856
Registriert: Mo 11. Sep 2006, 19:01

Re: /bin/ps -A zeigt bereits beendete Programme an. Warum?

Beitrag von theo »

ps aux | grep 'Z'

STAT:
D uninterruptible sleep (usually IO)
I Idle kernel thread
R running or runnable (on run queue)
S interruptible sleep (waiting for an event to complete)
T stopped by job control signal
t stopped by debugger during the tracing
W paging (not valid since the 2.6.xx kernel)
X dead (should never be seen)
Z defunct ("zombie") process, terminated but not reaped by its parent

Epcop
Beiträge: 159
Registriert: Di 29. Mai 2012, 09:36

Re: /bin/ps -A zeigt bereits beendete Programme an. Warum?

Beitrag von Epcop »

Gestartet habe ich es so:

Code: Alles auswählen

      Process := TProcess.Create(nil);
      try
        Process.Executable := '../testprogramm';
        Process.Parameters.Add(IntToStr(a)); //id
        Process.Execute;
        // ?? Process.ExitStatus;
       // ?? Process.ExitCode;
      finally
        Process.Free;
      end;
Interessant, dass das bei Mint anders ist!?

Code: Alles auswählen

ps aux | grep 'Z'
Auch interessant. Das heißt, möchte man Wissen ob ein Prozess gestartet ist, reicht es nicht ps -A aufzurufen. Sondern, muss den Prozess auch über ps aux | grep 'Z' aufrufen. Und ggf. die Summe der gesuchten Prozesse von ps aux | grep 'Z' von der Summe der gesuchten Prozesse von ps -A abziehen. Erst dann hat man die tatsächlich laufenden Prozess(e).



Das mit dem Exit Status habe ich nicht verstanden.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2805
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: /bin/ps -A zeigt bereits beendete Programme an. Warum?

Beitrag von m.fuchs »

Epcop hat geschrieben: Di 25. Mär 2025, 12:49

Code: Alles auswählen

  Process.Executable := '../testprogramm';
  Process.Parameters.Add(IntToStr(a)); //id
  Process.Execute;
   
Interessant, dass das bei Mint anders ist!?
Ist bei Mint nicht anders, dir fehlt eine Option die ich habe:

Code: Alles auswählen

Process.Options := Process.Options + [poWaitOnExit];
Wenn du das einbaust, dann sollte kein Zombie mehr auftauchen.
Nachteil: dein Programm wartet an der Stelle, bis der Prozess beendet ist. Also müsstest du das ganze in einen Thread auslagern.
Vorteil: du kannst dir die Abfrage von ps ersparen, weil du auch so weißt ob der Prozess durch ist.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Epcop
Beiträge: 159
Registriert: Di 29. Mai 2012, 09:36

Re: /bin/ps -A zeigt bereits beendete Programme an. Warum?

Beitrag von Epcop »

Hier ist erstmal eine Variante, die schonmal ganz gut aussieht:

Code: Alles auswählen

function LaufendesProgrammZaehlen(const ExeName: string): Integer;
var
  Process: TProcess;
  Output: TStringList;
  i: Integer;
  ps_zaehler, zombie_zaehler: integer;
begin
  Result := 0;
  ps_zaehler     := 0;
  zombie_zaehler := 0;

  // === Alle gesuchten Prozesse zählen
  Process := TProcess.Create(nil);
  Output := TStringList.Create;
  try
    Process.Executable := '/bin/ps';  // Für Windows genügt hier taskkill   ?? Ohne ZombieProzesse
    Process.Parameters.Add('-A');     // Windows braucht hier auch was anderes todo
    Process.Options := Process.Options + [poWaitOnExit, poUsePipes];
    Process.Execute;
    Output.LoadFromStream(Process.Output);

    // Zähle Vorkommen von ExeName in der Ausgabe
    for i := 0 to Output.Count - 1 do
      if Pos(ExeName, Output[i]) > 0 then
        ps_zaehler := ps_zaehler+1;
  finally
    Process.Free;
    Output.Free;
  end;


  // === Alle Zombie Prozesse zählen
  Process := TProcess.Create(nil);
  Output := TStringList.Create;
  try
    Process.Executable := '/bin/sh';     //ps -aux | grep "Z" geht nicht direkt! Muss über Shell laufen
    Process.Parameters.Add('-c');
    Process.Parameters.Add('ps -aux | grep "Z"');
    Process.Options := Process.Options + [poWaitOnExit, poUsePipes];
    Process.Execute;
    Output.LoadFromStream(Process.Output);

    // Zähle Vorkommen von ExeName in der Ausgabe
    for i := 0 to Output.Count - 1 do
      if Pos(ExeName, Output[i]) > 0 then
        zombie_zaehler := zombie_zaehler+1;
  finally
    Process.Free;
    Output.Free;
  end;

  Result := ps_zaehler-zombie_zaehler ;
  ShowMessage('Anzahl der laufenden Instanzen von ' + ExeName + ': ' + IntToStr(Result));

end;
Threads sind auch eine gute Idee. Aber für meine Anwendungsfall etwas übertrieben. Ich brauche das nur einmalig und selten.

Das mit ps war spannend, deswegen gleich Funktion gebaut. Dann kann es jeder nutzen wer mag :)

Antworten