fork - erzeugt einen Kindprozess
Standard-C-Bibliothek (libc, -lc)
ÜBERSICHT
#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)
ÜBERSETZUNG
Die deutsche Übersetzung dieser Handbuchseite wurde von
Martin Schulze <joey@infodrom.org>, Martin Eberhard Schauer
<Martin.E.Schauer@gmx.de>, Holger Wansing
<linux@wansing-online.de>, Mario Blättermann
<mario.blaettermann@gmail.com> und Helge Kreutzmann
<debian@helgefjell.de> 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.