Warum ist der Standardprozess Erstellungsmechanismus Gabel?

46

Der UNIX-Systemaufruf zur Prozesserstellung, fork (), erstellt einen untergeordneten Prozess, indem der übergeordnete Prozess kopiert wird. Meines Wissens folgt darauf fast immer ein Aufruf von exec (), um den Speicherbereich des untergeordneten Prozesses (einschließlich Textsegment) zu ersetzen. Das Kopieren des Speicherplatzes der Eltern in fork () erschien mir immer verschwenderisch (obwohl mir klar ist, dass die Verschwendung minimiert werden kann, indem die Speichersegmente beim Schreiben kopiert werden, sodass nur Zeiger kopiert werden). Wie auch immer, weiß jemand, warum dieser Duplizierungsansatz für die Erstellung von Prozessen erforderlich ist?

Ellen Spertus
quelle
3
Beachten Sie, dass die fork(2)Manpage unter Linux sagt: Under Linux, fork() is implemented using copy-on-write pages, so the only penalty that it incurs is the time and memory required to duplicate the parent's page tables, and to create a unique task structure for the child. Ich stelle mir vor (weiß aber nicht genau), dass dies bei anderen modernen Unix-Varianten der Fall ist.
Larsks
4
Das Original, PDP-11 Unix, hat wirklich alle Bytes eines Fork-Prozesses kopiert: Aber es hatte nur 64 KB ausführbare Dateien und höchstens 64 KB Daten, also war es auch 1975 keine große Belastung Ich schätze, dass JEDES UNIX und UNIX-ähnliche seit etwa 1990 Textsegmente hat, die beim Schreiben kopiert wurden. Daher bin ich mir nicht einmal mehr sicher, warum Bücher und Artikel "Leistungsprobleme mit Gabel" verbreiten.
Bruce Ediger
Heutzutage wird fork ähnlich wie vfork implementiert ( openbsd.org/cgi-bin/… ). Es ist effizient, keine Sorge.
Aki
Beachten Sie auch, dass es viele Anwendungen gibt, bei denen Sie nach einem Fork nicht ausführen (oder zumindest nicht sofort ausführen): Denken Sie an Pipes und Webserver.
jfg956
Sie können, was ist, wäre langsam. Aber wie @cjm sagt, schauen Sie sich die Alternative an, die Microsoft für CreateProcess verwendet, mussten sie Threads frühzeitig implementieren (möglicherweise das Einzige, worauf sie hinauslaufen), da CreateProcess langsam ist. (Sie brauchten auch Fäden, weil sie selectkaputt waren, aber das ist eine andere Geschichte).
ctrl-alt-delor

Antworten:

57

Es ist die Schnittstelle zu vereinfachen. Die Alternative zu forkund execwäre so etwas wie die CreateProcess- Funktion von Windows . Beachten Sie, wie viele Parameter vorhanden CreateProcesssind, und viele davon sind Strukturen mit noch mehr Parametern. Dies liegt daran, dass alles , was Sie über den neuen Prozess steuern möchten, übergeben werden muss CreateProcess. In der Tat, CreateProcessnicht genügend Parameter, so Microsoft hinzufügen hatte CreateProcessAsUser und CreateProcessWithLogonW .

Mit dem fork/execModell benötigen Sie nicht alle diese Parameter. Stattdessen bleiben bestimmte Attribute des Prozesses übergreifend erhalten exec. Auf diese Weise können Sie die forkgewünschten Prozessattribute ändern (mit denselben Funktionen, die Sie normalerweise verwenden würden) und dann exec . Hat unter Linux forkkeine Parameter und execvenur 3: das auszuführende Programm, die Befehlszeile und seine Umgebung. (Es gibt noch andere execFunktionen, aber sie sind nur Wrapper, execvedie von der C-Bibliothek bereitgestellt werden, um allgemeine Anwendungsfälle zu vereinfachen.)

Wenn Sie einen Prozess mit einem anderen aktuellen Verzeichnis starten: fork, chdir, exec.

Wenn Sie möchten , Umleitung stdin / stdout: fork, Schließen / Öffnen von Dateien, exec.

Wenn Sie Switch - Benutzer wollen: fork, setuid, exec.

All diese Dinge können nach Bedarf kombiniert werden. Wenn jemand mit einer neuen Art von Prozess - Attribute aufkommt, müssen Sie nicht ändern forkund exec.

Wie bereits erwähnt, verwenden die meisten modernen Unixe Copy-on-Write, sodass forkkein erheblicher Overhead anfällt .

cjm
quelle
16
Hervorragende Erklärung. "Diejenigen, die UNIX nicht verstehen, sind verdammt, es schlecht neu zu erfinden." - Henry Spencer
Kyle Jones
1
Vielen Dank! Haben Sie zufällig eine Referenz?
Ellen Spertus
1
@Aki, nö, CreateProcess () erstellt buchstäblich einen neuen Prozess und baut ihn von Grund auf neu auf, ohne zu forken.
Psusi
2
Aber muss es nicht irgendwo in Unix ein Äquivalent zu CreateProcess () geben? Wie entsteht sonst der allererste Prozess? Im Gegensatz zu einem mythologischen Schöpfergott kann sich der erste Prozess nicht aus dem Nichts lösen. ;-)
Steven Montag
2
@StevenMonday, ja, aber es befindet sich im Initialisierungscode des Kernels und ist nicht von außen zugänglich. Es werden nicht alle diese Parameter benötigt, da fast alles fest codiert ist. Es kann nur die Prozess-ID 1 (auch als Init-Prozess bezeichnet) erstellt werden. Danach werden Prozesse nur durch Gabeln erstellt.
cjm 08.02.12
5

Zusätzlich zur Antwort des cjm definiert die Single Unix Specification eine Funktion mit dem Namen vfork(). Diese Funktion funktioniert wie Fork, außer dass der Fork-Prozess ein undefiniertes Verhalten aufweist, wenn er etwas anderes ausführt, als eine ausführbare Funktion aufzurufen oder aufzurufen _exit().

So ziemlich die einzige Verwendung mit definiertem Verhalten ist:

pid_t ret = vfork();
if(ret == 0)
{
    exec(...);
    _exit(EXIT_FAILURE); //in case exec failed for any reason.
}

Also, was macht vforkdas? Es ist eine preiswerte fork. Bei Implementierungen ohne Copy-on-Write teilt sich der resultierende Prozess den Speicherplatz mit dem ursprünglichen Prozess (daher das undefinierte Verhalten). Bei Implementierungen mit Copy-on-Write vforkdarf identisch sein fork(), da Copy-on-Write-Implementierungen schnell sind.

Es gibt auch die optionale posix_spawnFunktion (und eine posix_spawnpFunktion), mit der ein neuer Prozess direkt erstellt werden kann. (Es ist auch zulässig, sie mit einem Bibliotheksaufruf unter Verwendung von forkund zu execimplementieren. Eine Beispielimplementierung wird bereitgestellt.)

Kevin Cathcart
quelle