Prozesse und Prozessverwaltung


Was sind Prozesse?

Ein Prozeß ist ein laufendes Programm. Er besteht aus Eine Liste von laufenden Prozesse können Sie mittels ps bekommen: Wichtig ist, daß jeder Prozeß eine PID hat.

Prozesse mittels system() erzeugen

Die Funktion system() ruft eine Subshell auf, und übergibt ihr ihre Argumente zur Ausführung. Ergebnis von system() ist der Rückgabecode des Kind-Prozesses:
if (system("who -r")) {
    warn "Probleme mit system()\n";
}

Prozesse mittels Backticks erzeugen

Sind Sie mehr an der (Standard-)Ausgabe der Subshell interessiert, können Sie Backticks verwenden:
$run_level = `who -r`;
@psliste   = `ps -ef`;
$result    = `$unix_commands`;

Prozesse clonen mit fork()

Ein Prozeß kann mit der Funktion fork() geklont werden. Als einzige Funktion hat fork() zwei verschiedene Rückgabewerte: Einen im Eltern-Prozeß (PID des Kind-Prozesses), und einen im Kind-Prozess (0). Da beide Prozesse denselben Code ausführen, kann durch den Rückgabecode von fork() unterschieden werden, ob der Kind- oder Eltern-Prozeß gerade dran ist. Beide Prozesse laufen parallel weiter.

$retval = fork();
if ($retval == -1) {
    # fork() failed
    die "fork() failed: $!\n";
} elsif ($retval == 0) {
    # child process
    print "Wir sind Kind-Prozess\n";
    exit 0;
} else {
    # parent process
    print "Wir sind Eltern-Prozess\n";
    exit 0;
}

Neues Programm mit exec()

Damit nicht beide Prozesse (Kind- und Eltern-Prozess) den gleichen Code ausführen müssen, sollten Sie z.B. den Kind-Prozess mit einem anderen Code überlagern. Sie können mit der Funktion exec() eine Programm-Datei laden, und ausführen:
$retval = fork();
if ($retval == -1) {
    # fork() failed
    die "fork() failed: $!\n";
} elsif ($retval == 0) {
    # child process
    print "Wir sind Kind-Prozess\n";
    exec("/bin/sh", "-sh");
    exit 1;   # Normally not reached!
} else {
    # parent process
    print "Wir sind Eltern-Prozess\n";
    exit 0;
}

Auf Kinder warten mit wait()

Normalerweise laufen nach fork() Eltern- und Kind-Prozess parallel weiter. Nun kann es u.U. wünschenswert sein, wenn z.B. der Eltern-Prozess auf das Ende des Kind-Prozesses warten könnte. So etwas tut die Shell ja ständig, wenn sie ein Kommando (ohne das abschliessende &) ausfüuhrt.

Ein Prozeß kann auf ein Kind-Prozess warten, indem er die Funktion wait() verwendet. wait() hält die Ausführung des Aufrufers solange an, bis daß der Kind-Prozess sich beendet. Danach kehrt wait() beim Aufrufer zurück. Man sagt auch, daß wait() blockiert:

$retval = fork();
if ($retval == -1) {
    # fork() failed
    die "fork() failed: $!\n";
} elsif ($retval == 0) {
    # child process
    print "Wir sind Kind-Prozess\n";
    exec("/bin/sh", "-sh");
    exit 1;   # Normally not reached!
} else {
    # parent process
    print "Wir sind Eltern-Prozess\n";
    wait();
    print "Kind-Prozess ist beendet. Es geht weiter!\n";
    print "Rückgabecode war: $?\n";
    exit 0;
}

Zombies vermeiden

Ein Zombie entsteht, wenn ein Eltern-Prozess zu beschäftigt ist, um auf den Tod eines seiner Kinder zu wait()en. Der Kind-Prozess hat schon exit() aufgerufen, und möchte nun gerne seinen Rückgabecode loswerden. Er verharrt im Zombie Zustand.

Warum holt der Eltern-Prozeß den Rückgabecode des Zombie nicht ab? Weil er z.B. in einer Schleife auf andere Ereignisse wartet (z.B. accept() bei Client-Server), und gerade nicht bereit ist, wait() aufzurufen.

Zombies lassen sich durch folgenden Trick vermeiden:

$SIG{'CHLD'} = 'reaper';

sub reaper {
    wait();     # ein zombie abholen
}

Vorherige Seite, Nächste Seite, Index, Hauptindex.


Copyright © 1997/08/16 by Farid Hajji.