fork - erzeugt einen Kindprozess
Standard-C-Bibliothek (
libc,
-lc)
#include <unistd.h>
pid_t fork(void);
fork() erzeugt einen neuen Prozess, indem der aufrufende Prozess
dupliziert wird. Der neue Prozess wird als das
Kind bezeichnet. Der
aufrufende Prozess wird als
Elternprozess bezeichnet.
Der Kind- und der Elternprozess laufen in separaten Speicherbereichen. Zum
Zeitpunkt von
fork() haben beide Speicherbereiche den gleichen Inhalt.
Speicherschreibvorgänge, Datei-Mappings (
mmap(2)) und Aufhebung
von Mappings (
munmap(2)) eines Prozesses beeinflussen den jeweiligen
anderen Prozess nicht.
Der Kindprozess ist ein exaktes Duplikat des Elternprozesses, mit folgenden
Ausnahmen:
- •
- Das Kind hat seine eigene eindeutige Prozesskennung, die
mit keiner Kennung irgendeiner existierenden Prozessgruppe oder Sitzung
übereinstimmt ( setpgid(2)).
- •
- Die Elternprozesskennung des Kindes ist die gleiche wie die
Prozesskennung des Elternprozesses.
- •
- Das Kind erbt keine Speichersperren (mlock(2),
mlockall(2)) des Elternprozesses.
- •
- Für das Kind wird die Nutzung von Prozessressourcen
( getrusage(2)) und Zähler für CPU-Zeiten (
times(2)) auf null zurückgesetzt.
- •
- Die Menge der für das Kind anstehenden Signale ist
anfangs leer ( sigpending(2)).
- •
- Das Kind erbt keine Semaphore-Einstellungen von seinem
Elternprozess ( semop(2)).
- •
- Das Kind erbt keine prozess-zugeordneten Datensatzsperren
von seinem Elternprozess ( fcntl(2)). (Allerdings erbt es offene
Dateideskriptionssperren von fcntl(2) und flock(2)-Sperren
von seinem Elternprozess.)
- •
- Das Kind erbt keine Timer von seinem Elternprozess
(setitimer(2), alarm(2), timer_create(2)).
- •
- Das Kind erbt keine ausstehenden asynchronen
E/A-Operationen von seinem Elternprozess ( aio_read(3),
aio_write(3)), auch asynchrone E/A-Kontexte des Elternprozesses
werden nicht vererbt (siehe io_setup(2)).
Die Prozessattribute in der vorstehenden Liste werden allesamt in POSIX.1
beschrieben. Eltern- und Kindprozess unterscheiden sich auch in den folgenden
Linux-spezifischen Prozessattributen:
- •
- Das Kind erbt keine Nachrichten über
Verzeichnisänderungen (directory change notifications, dnotify) von
seinem Elternprozess (siehe die Beschreibung von F_NOTIFY in
fcntl(2)).
- •
- Die Einstellung PR_SET_PDEATHSIG von prctl(2)
wird zurückgesetzt, sodass das Kind kein Signal empfängt,
wenn sein Elternprozess terminieren.
- •
- Der voreingestellte Wert für den Timer-Spielraum
(»timer slack«) wird auf den aktuellen Timer-Spielraum des
Elternprozesses gesetzt. Siehe die Beschreibung von
PR_SET_TIMERSLACK in prctl(2).
- •
- Speicher-Mappings, die mit dem madvise(2)-Schalter
MADV_DONTFORK markiert wurden, werden nicht über einen
Aufruf von fork() hinweg vererbt.
- •
- Speicher in dem Adressbereich, der mit dem
madvise(2)-Schalter MADV_WIPEONFORK markiert ist, wird nach
einem fork() im Kind genullt. (Die Einstellung
MADV_WIPEONFORK verbleibt für diese Adressbereiche im
Kind.)
- •
- Das Terminierungssignal des Kindes ist immer SIGCHLD
(siehe clone(2)).
- •
- Die von ioperm(2) gesetzten Bits für
Portzugriffe werden nicht an das Kind vererbt, stattdessen muss das Kind
benötigte Bits mittels ioperm(2) aktivieren.
Beachten Sie die folgenden weiteren Punkte:
- •
- Der Kindprozess wird mit einem einzigen Thread erstellt
– demjenigen, der fork aufrief. Der gesamte virtuelle
Adressraum des Elternprozesses wird im Kind repliziert,
einschließlich der Zustände der Mutexe, Zustandsvariablen
und anderer »pthread«-Objekte; die Verwendung von
pthread_atfork(3) kann für die Behandlung von dadurch
verursachten Problemen hilfreich sein.
- •
- Nach einem fork() in einem Multithread-Programm kann
das Kind sicher nur async-signal-safe-Funktionen aufrufen (siehe
signal-safety(7)), bis es execve(2) aufruft.
- •
- Das Kind erbt Kopien der Menge der offenen
Dateideskriptoren des Elternprozesses. Jeder Deskriptor des Kindes bezieht
sich auf die gleichen offenen Dateideskriptoren (siehe open(2)) wie
der entsprechende Dateideskriptor in dem Elternprozess. Dies bedeutet,
dass die beiden Dateideskriptoren die Statusschalter geöffneter
Dateien, den Datei-Offset und signalgesteuerte E/A-Attribute (siehe die
Beschreibung von F_SETOWN und F_SETSIG in fcntl(2))
gemeinsam nutzen.
- •
- Das Kind erbt Kopien der Menge der Deskriptoren des
Elternprozesses für offene Nachrichten-Warteschlangen (siehe
mq_overview(7)). Jeder Dateideskriptor des Kindes bezieht sich auf
die gleiche Nachrichtenwarteschlangendeskription wie der entsprechende
Dateideskriptor in dem Elternprozess. Das bedeutet, dass die beiden
Dateideskriptoren die gleichen Schalter ( mq_flags) gemeinsam
nutzen.
- •
- Das Kind erbt Kopien der Menge der offenen
Verzeichnis-Streams des Elternprozesses (siehe opendir(3)). POSIX.1
besagt, dass die entsprechenden Verzeichnis-Streams auf die gleiche
Position zeigen können; unter Linux/Glibc tun sie es
nicht.
Bei Erfolg wird im Elternprozess die PID des Kindprozesses zurückgegeben
und in dem Kind 0. Bei Fehlern wird dem Elternprozess -1 zurückgegeben,
kein Kindprozess erzeugt und
errno gesetzt, um den Fehler anzuzeigen.
- EAGAIN
- Eine systembedingte Begrenzung der Anzahl der Threads wurde
erreicht. Es gibt eine Reihe von Begrenzungen, die diesen Fehler
auslösen können:
- •
- die weiche Ressourcenbegrenzung RLIMIT_NPROC
(mittels setrlimit(2) gesetzt), die die Anzahl der Prozesse und
Threads für eine reale Benutzerkennung begrenzt, wurde
erreicht;
- •
- die systemweite Kernelbegrenzung der Anzahl an Prozessen
und Threads, /proc/sys/kernel/threads-max, wurde erreicht (siehe
proc(5));
- •
- die maximale Anzahl an PIDs,
/proc/sys/kernel/pid_max, wurde erreicht (siehe
proc(5));
- •
- die durch den Cgroup-Controller »process
number« erzwungende PID-Begrenzung ( pids.max) wurde
erreicht.
- EAGAIN
- Die aufrufende Instanz agiert gemäß der
SCHED_DEADLINE-Scheduling-Regeln und hat den Schalter reset-on-fork
nicht gesetzt. Siehe sched(7).
- ENOMEM
-
fork() konnte wegen Speicherknappheit die
erforderlichen Kernel-Strukturen nicht anlegen.
- ENOMEM
- Es wurde versucht, einen Kindprozess in einem
PID-Namensraum, dessen »init«-Prozess sich beendet hat, zu
erstellen. Siehe pid_namespaces(7).
- ENOSYS
-
fork() wird auf dieser Plattform nicht
unterstützt (beispielsweise Hardware ohne eine
Speicher-Management-Einheit).
-
ERESTARTNOINTR (seit Linux 2.6.17)
- Ein Systemaufruf wurde durch ein Signal unterbrochen und
wird neu gestartet. (Dies wird nur während einer Verfolgung
sichtbar sein.)
POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD.
Unter Linux ist
fork() mittels »copy-on-write«-Seiten
implementiert, sodass der einzige Nachteil von
fork() die Zeit und der
Speicher ist, der benötigt wird, um die Page Tables des Elternprozesses
zu kopieren und eine eindeutige Task-Struktur für das Kind anzulegen.
Der Glibc-Wrapper für
fork() wird als Teil der
NPTL-Threading-Implementierung bereitgestellt. Seit Version 2.3.3 der Glibc
ruft der
fork()-Wrapper nicht mehr den Kernel-Systemaufruf
fork() auf, sondern
clone(2) mit Schaltern, die das Gleiche
bewirken wie der traditionelle Systemaufruf. (Ein Aufruf von
fork() ist
gleichbedeutend mit einem Aufruf von
clone(2), bei dem für
flags nur
SIGCHLD angegeben wird.) Der Glibc-Wrapper ruft alle
Fork-Handler auf, die mittels
pthread_atfork(3) eingerichtet wurden.
Siehe
pipe(2) und
wait(2) für weitere Beispiele.
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main(void)
{
pid_t pid;
if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) {
perror("signal");
exit(EXIT_FAILURE);
}
pid = fork();
switch (pid) {
case -1:
perror("fork");
exit(EXIT_FAILURE);
case 0:
puts("Kind beendet sich.");
exit(EXIT_SUCCESS);
default:
printf("Kind ist PID %jd\n", (intmax_t) pid);
puts("Elternprozess beendet sich.");
exit(EXIT_SUCCESS);
}
}
clone(2),
execve(2),
exit(2),
setrlimit(2),
unshare(2),
vfork(2),
wait(2),
daemon(3),
pthread_atfork(3),
capabilities(7),
credentials(7)
Die deutsche Übersetzung dieser Handbuchseite wurde von Martin Schulze
<
[email protected]>, Martin Eberhard Schauer
<
[email protected]>, Holger Wansing
<
[email protected]>, Mario Blättermann
<
[email protected]> und Helge Kreutzmann
<
[email protected]> erstellt.
Diese Übersetzung ist Freie Dokumentation; lesen Sie die
GNU
General Public License Version 3 oder neuer bezüglich der
Copyright-Bedingungen. Es wird KEINE HAFTUNG übernommen.
Wenn Sie Fehler in der Übersetzung dieser Handbuchseite finden, schicken
Sie bitte eine E-Mail an die
Mailingliste
der Übersetzer