Wie startet ein Prozess einen anderen?
Ein Prozess ist ein laufendes Programm mit eigenem Speicher. Unter Linux startet jeder Prozess bis auf den ersten ein anderer Prozess, und das Mittel dafür heißt fork.
Tippen Sie in der Shell ls, dann erzeugt die Shell einen neuen Prozess, lädt ls hinein und wartet auf sein Ende. Diese drei Schritte lernen Sie jetzt als eigene C-Aufrufe kennen.
Am Ende dieser Lektion
Notiz
Ich kann erklären, wie ein Prozess mit fork, exec und wait einen anderen startet.
Schlüsselwörter
| Begriff | Was er bedeutet | Beispiel |
|---|---|---|
| Prozess | ein laufendes Programm mit eigenem Speicher | |
| fork | erzeugt eine Kopie des laufenden Prozesses | fork() |
| exec | ersetzt das laufende Programm durch ein anderes | execlp |
| wait | wartet, bis ein Kindprozess endet | waitpid |
| Exit-Status | die Zahl, die ein Prozess beim Ende meldet | |
| Zombie | ein beendeter Prozess, dessen Status niemand abgeholt hat |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
fork kopiert den laufenden Prozess
Der Aufruf fork() erzeugt eine fast genaue Kopie des Prozesses, das Kind. Beide laufen danach an derselben Stelle im Code weiter.
Nur der Rückgabewert unterscheidet sie: Im Kind ist er 0, im Elternprozess die Nummer des Kindes. Mit waitpid wartet der Elternprozess, bis das Kind endet, und holt dessen Exit-Status ab.
Das Programm kind.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void) {
pid_t kind = fork();
if (kind == 0) {
printf("Kind: ich laufe\n");
exit(3);
}
int status;
waitpid(kind, &status, 0);
printf("Elternteil: Kind endete mit Status %d\n", WEXITSTATUS(status));
return 0;
}
In den Arbeitsordner wechseln
mkdir -p ~/csys && cd ~/csysHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Programm in eine Datei schreiben
printf '#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <sys/wait.h>\n\nint main(void) {\n pid_t kind = fork();\n if (kind == 0) {\n printf("Kind: ich laufe\\n");\n exit(3);\n }\n int status;\n waitpid(kind, &status, 0);\n printf("Elternteil: Kind endete mit Status %%d\\n", WEXITSTATUS(status));\n return 0;\n}\n' > kind.cHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Programm übersetzen
gcc -o kind kind.cHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Programm starten
./kindHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
exec ersetzt das Programm im Prozess
Eine Kopie desselben Programms hilft meist nicht. Meist soll das Kind ein anderes Programm laufen lassen. Dafür dient exec.
Es lädt ein neues Programm in den Prozess und wirft das alte weg. Danach läuft nichts mehr vom alten Code. Die Shell macht genau das: erst fork, dann exec im Kind, dann wait im Elternprozess.
Ein Programm mit fork und exec schreiben
printf '#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <sys/wait.h>\n\nint main(void) {\n pid_t kind = fork();\n if (kind == 0) {\n execlp("echo", "echo", "Kind: jetzt läuft echo", NULL);\n exit(99);\n }\n int status;\n waitpid(kind, &status, 0);\n printf("Elternteil: Status %%d\\n", WEXITSTATUS(status));\n return 0;\n}\n' > startet.cHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Programm übersetzen
gcc -o startet startet.cHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Programm starten
./startetHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Der Exit-Status sagt, wie ein Prozess endete
Jeder Prozess meldet beim Ende eine Zahl, den Exit-Status. Die 0 heißt Erfolg, jede andere Zahl einen Fehler.
Wird ein Prozess durch ein Signal beendet, meldet die Shell 128 plus die Signalnummer. Solange der Elternprozess den Status nicht abgeholt hat, bleibt der beendete Prozess als Zombie im System.
Beispiel: Statuszahlen in der Shell
| Status | Bedeutung |
|---|---|
| 0 | Erfolg |
| 1 | ein allgemeiner Fehler |
| 3 | eine Zahl, die das Programm selbst gewählt hat |
| 134 | durch das Signal 6 beendet, 128 + 6 |
| 139 | durch das Signal 11 beendet, 128 + 11 |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Eine Shell mit dem Status 3 beenden
sh -c "exit 3"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Den Status des letzten Befehls anzeigen
echo $?Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Ein häufiger Fehler
Warnung
Viele glauben, fork starte ein neues Programm. fork kopiert nur den laufenden Prozess, danach läuft derselbe Code zweimal. Erst exec lädt ein anderes Programm. Wer nur fork ruft, hat zwei gleiche Prozesse und kein neues Programm.